{"version":3,"file":"options-loaders.3280c846.js","mappings":"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","sources":["webpack://@finviz/website/./js/app/header/utils.ts","webpack://@finviz/website/./js/main/modules/options/constants/common.ts","webpack://@finviz/website/./js/main/modules/options/services/api.ts","webpack://@finviz/website/./js/main/modules/options/loaders.tsx","webpack://@finviz/website/./js/main/modules/options/types.tsx","webpack://@finviz/website/./js/main/modules/options/utils/query.ts"],"sourcesContent":["import * as dateFns from 'date-fns'\r\n\r\n/**\r\n * Check if a given date is DST in the US\r\n * - begins on the second Sunday in March\r\n * - ends on the first Sunday in November\r\n *\r\n * Keep in sync with https://github.com/finvizhq/charts/blob/master/app/utils.ts\r\n */\r\nexport function getIsDstInNy(date: Date) {\r\n const dayNumber = date.getDate()\r\n const monthIndex = date.getMonth()\r\n const dayOfWeek = date.getDay()\r\n const previousSunday = dayNumber - dayOfWeek\r\n if (monthIndex < 2 || monthIndex > 10) {\r\n return false\r\n }\r\n if (monthIndex > 2 && monthIndex < 10) {\r\n return true\r\n }\r\n return monthIndex === 2 ? previousSunday >= 8 : previousSunday <= 0\r\n}\r\n\r\nexport function getDate(seed?: string | number | Date | null) {\r\n var date = seed != null ? new Date(seed) : new Date()\r\n const dateAsNY = new Date(\r\n date.getUTCFullYear(),\r\n date.getUTCMonth(),\r\n date.getUTCDate(),\r\n date.getUTCHours() - 5,\r\n date.getUTCMinutes(),\r\n date.getUTCSeconds()\r\n )\r\n const isDst = getIsDstInNy(dateAsNY)\r\n\r\n if (isDst) {\r\n dateAsNY.setUTCHours(dateAsNY.getUTCHours() + 1)\r\n }\r\n\r\n return dateAsNY\r\n}\r\n\r\nfunction getWeekDay(date: Date) {\r\n return date.toLocaleDateString('en-US', { weekday: 'short' })\r\n}\r\n\r\nfunction getMonth(date: Date, uppercase = true) {\r\n const name = date.toLocaleDateString('en-US', { month: 'short' })\r\n return uppercase ? name.toUpperCase() : name\r\n}\r\n\r\nfunction getDay(date: Date) {\r\n return date.getDate().toString().padStart(2, '0')\r\n}\r\n\r\nfunction getTime(date: Date) {\r\n return date.toLocaleString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })\r\n}\r\n\r\nenum TimeFormat {\r\n long,\r\n short,\r\n dateOnly,\r\n timeOnly,\r\n}\r\n\r\nexport type TimeFormatType = keyof typeof TimeFormat\r\n\r\nexport function getFormattedDateString(date: Date = getDate(), format: TimeFormatType = 'long') {\r\n switch (TimeFormat[format]) {\r\n case TimeFormat.long:\r\n return `${getWeekDay(date)} ${getMonth(date)} ${getDay(date)} ${date.getFullYear()} ${getTime(date)} ET`\r\n case TimeFormat.short:\r\n return `${getWeekDay(date)} ${getMonth(date)} ${getDay(date)} ${getTime(date)}`\r\n case TimeFormat.dateOnly:\r\n return `${getMonth(date, false)} ${getDay(date)}`\r\n case TimeFormat.timeOnly:\r\n return getTime(date)\r\n }\r\n}\r\n\r\nexport function formatDate(value: Date | unknown, inputOrOutputFormat: string, outputFormat?: string): string {\r\n return dateFns.format(\r\n dateFns.isDate(value) ? (value as Date) : dateFns.parse(`${value}`, inputOrOutputFormat, new Date()),\r\n outputFormat ?? inputOrOutputFormat\r\n )\r\n}\r\n\r\nexport function isPremarket(date: Date = getDate(), isPremium = FinvizSettings.hasUserPremium) {\r\n const dayOfWeek = date.getDay()\r\n const min = date.getMinutes()\r\n const hours = date.getHours()\r\n\r\n if (isPremium && dayOfWeek !== 0 && dayOfWeek !== 6 && (hours === 7 || hours === 8 || (hours === 9 && min < 30))) {\r\n return true\r\n }\r\n return false\r\n}\r\n\r\nexport function isAftermarket(date: Date = getDate(), isPremium = FinvizSettings.hasUserPremium) {\r\n const dayOfWeek = date.getDay()\r\n const min = date.getMinutes()\r\n\r\n if (\r\n isPremium &&\r\n dayOfWeek !== 0 &&\r\n dayOfWeek !== 6 &&\r\n (date.getHours() === 16 || date.getHours() === 17 || (date.getHours() === 18 && min < 30))\r\n ) {\r\n return true\r\n }\r\n return false\r\n}\r\n\r\n/**\r\n * https://www.nyse.com/markets/hours-calendars\r\n */\r\nconst HOLIDAY_DATES = [\r\n {\r\n label: \"New Year's Day\",\r\n test: (day: number, month: number) => month === 1 && day === 1,\r\n },\r\n {\r\n label: 'Martin Luther King, Jr. Day',\r\n test: (day: number, month: number) => month === 1 && day === 15,\r\n },\r\n {\r\n label: 'Presidents Day',\r\n test: (day: number, month: number) => month === 2 && day === 19,\r\n },\r\n {\r\n label: 'Good Friday',\r\n test: (day: number, month: number) => month === 3 && day === 29,\r\n },\r\n {\r\n label: 'Memorial Day',\r\n test: (day: number, month: number) => month === 5 && day === 27,\r\n },\r\n {\r\n label: 'Juneteenth Holiday',\r\n test: (day: number, month: number) => month === 6 && day === 19,\r\n },\r\n {\r\n label: 'Early Close',\r\n test: (day: number, month: number, hours: number) => month === 7 && day === 3 && hours >= 13,\r\n },\r\n {\r\n label: 'Independence Day',\r\n test: (day: number, month: number) => month === 7 && day === 4,\r\n },\r\n {\r\n label: 'Labor Day',\r\n test: (day: number, month: number) => month === 9 && day === 2,\r\n },\r\n {\r\n label: 'Thanksgiving Day',\r\n test: (day: number, month: number) => month === 11 && day === 28,\r\n },\r\n {\r\n label: 'Day after Thanksgiving (closed from 1 PM)',\r\n test: (day: number, month: number, hours: number) => month === 11 && day === 29 && hours >= 13,\r\n },\r\n {\r\n label: 'Christmas Day',\r\n test: (day: number, month: number) => month === 12 && day === 25,\r\n },\r\n]\r\n\r\nexport function getHoliday(date: Date = getDate()) {\r\n var day = date.getDate()\r\n var month = date.getMonth() + 1\r\n var hours = date.getHours()\r\n\r\n return HOLIDAY_DATES.find((holiday) => holiday.test(day, month, hours))\r\n}\r\n\r\nexport function isHoliday(date: Date = getDate()) {\r\n return !!getHoliday(date)\r\n}\r\n\r\nexport function isMarketOpen(date: Date = getDate(), isPremium = FinvizSettings.hasUserPremium) {\r\n if (isPremarket(date, isPremium) || isAftermarket(date, isPremium) || isHoliday(date)) {\r\n return false\r\n }\r\n\r\n const dayOfWeek = date.getDay()\r\n const hour = date.getHours()\r\n const minute = date.getMinutes()\r\n\r\n const isWeekend = dayOfWeek === 0 || dayOfWeek === 6\r\n // Day starts at 9:30\r\n const dayStarted = hour === 9 ? minute >= 30 : hour >= 10\r\n // Ends at 16:00\r\n const dayEnded = hour >= 16\r\n\r\n return !isWeekend && dayStarted && !dayEnded\r\n}\r\n\r\n// duplicate from charts/app/utils/helpers.ts , will be refactored in next PR\r\nexport function getEarningsDateSuffix(date: Date) {\r\n const hours = date.getHours()\r\n\r\n if (hours <= 9) {\r\n return 'BMO'\r\n } else if (hours >= 16) {\r\n return 'AMC'\r\n }\r\n\r\n return ''\r\n}\r\n","export const DATE_FORMAT_DB = 'yyyy-MM-dd'\r\nexport const DATE_FORMAT_INT = 'yyMMdd'\r\nexport const DATE_FORMAT_VIEW = 'MM/dd/yyyy'\r\nexport const DATE_FORMAT_VIEW_LONG = 'MMM dd, yyyy, hh:mm a'\r\nexport const DATE_FORMAT_SCATTER_PLOT = '%m/%d/%Y'\r\nexport const LINK_COLUMN_NAME = 'link'\r\n","import { apiRequest } from '../../../services/api'\r\nimport { Option, OptionsLoaderData, OptionsSubpage, OptionsView } from '../types'\r\n\r\nexport const EMPTY_RESPONSE: OptionsLoaderData = {\r\n ticker: null,\r\n view: OptionsView.ChainByDate,\r\n subpage: OptionsSubpage.Prices,\r\n options: [],\r\n lastClose: null,\r\n lastTime: null,\r\n expiries: [],\r\n currentExpiry: '',\r\n}\r\n\r\ninterface OptionsDataQuery {\r\n expiry?: string | null\r\n strike?: number | null\r\n filterLastClose?: boolean | null\r\n}\r\n\r\ninterface OptionsData {\r\n optionable: boolean\r\n options: Option[]\r\n lastClose: number | null\r\n lastTime: number | null\r\n}\r\n\r\nexport function optionsData(ticker: string, query?: OptionsDataQuery) {\r\n return apiRequest(`/api/options/${ticker}`, { query })\r\n}\r\n\r\nexport function expiriesData(ticker: string) {\r\n return apiRequest(`/api/options/${ticker}/expiries`)\r\n}\r\n\r\nexport function strikesData(ticker: string) {\r\n return apiRequest(`/api/options/${ticker}/strikes`)\r\n}\r\n","import { LoaderFunctionArgs, replace } from 'react-router-dom'\r\n\r\nimport { parseRouteInitData } from '../../util-routing'\r\nimport * as api from './services/api'\r\nimport {\r\n OptionsByDateLoader,\r\n OptionsByStrikeLoader,\r\n OptionsLoaderData,\r\n OptionsQuery,\r\n OptionsView,\r\n PlotLoader,\r\n} from './types'\r\nimport { OptionsParsedQuery, parseOptionsQuery } from './utils/query'\r\n\r\nexport async function loader(args: LoaderFunctionArgs) {\r\n const url = new URL(args.request.url)\r\n const parsedQuery = parseOptionsQuery(url.searchParams)\r\n\r\n /**\r\n * Add expiry query param on initial response\r\n */\r\n const isDateView = [OptionsView.ChainByDate, OptionsView.ListByDate].includes(parsedQuery.view)\r\n const expiry = parsedQuery.expiry\r\n // Do not remove the init element if we’re missing expiry, the loader will run again after redirect\r\n const initialResponse = parseRouteInitData({ removeElement: isDateView ? !!expiry : true })\r\n if (initialResponse) {\r\n const dateLoaderInit = initialResponse as OptionsByDateLoader\r\n if (isDateView && (!expiry || !dateLoaderInit.expiries.includes(expiry!))) {\r\n url.searchParams.set(OptionsQuery.Expiry, dateLoaderInit.currentExpiry)\r\n return replace(url.toString())\r\n }\r\n return initialResponse\r\n }\r\n\r\n switch (parsedQuery.view) {\r\n case OptionsView.Plot:\r\n return plotDataLoader(parsedQuery)\r\n case OptionsView.ChainByStrike:\r\n case OptionsView.ListByStrike:\r\n return optionsByStrikeLoader(parsedQuery)\r\n case OptionsView.ChainByDate:\r\n case OptionsView.ListByDate:\r\n default:\r\n return optionsByDateLoader(parsedQuery)\r\n }\r\n}\r\n\r\nasync function plotDataLoader(query: OptionsParsedQuery): Promise {\r\n const optionsData = await api.optionsData(query.ticker, { filterLastClose: true })\r\n\r\n if (!optionsData) return null\r\n\r\n return {\r\n view: OptionsView.Plot,\r\n subpage: query.type,\r\n ...optionsData,\r\n }\r\n}\r\n\r\nexport async function optionsByStrikeLoader(query: OptionsParsedQuery): Promise {\r\n try {\r\n const strikes = await api.strikesData(query.ticker)\r\n if (!strikes) return null\r\n\r\n const strike = query.strike && strikes.includes(query.strike) ? query.strike : strikes[0]\r\n const optionsData = await api.optionsData(query.ticker, { strike })\r\n\r\n if (!optionsData) return null\r\n\r\n return {\r\n // This is already guarded by a switch\r\n view: query.view as OptionsView.ChainByStrike | OptionsView.ListByStrike,\r\n subpage: query.type,\r\n ticker: query.ticker,\r\n strikes: strikes,\r\n currentStrike: strike,\r\n ...optionsData,\r\n }\r\n } catch {}\r\n\r\n return null\r\n}\r\n\r\nexport async function optionsByDateLoader(query: OptionsParsedQuery): Promise {\r\n try {\r\n const expiries = await api.expiriesData(query.ticker)\r\n if (!expiries) return null\r\n\r\n const expiry = query.expiry && expiries.includes(query.expiry) ? query.expiry : expiries[0]\r\n const optionsData = await api.optionsData(query.ticker, { expiry })\r\n\r\n if (!optionsData) return null\r\n\r\n return {\r\n // This is already guarded by a switch\r\n view: query.view as OptionsView.ChainByDate | OptionsView.ListByDate,\r\n subpage: query.type,\r\n ticker: query.ticker,\r\n expiries,\r\n currentExpiry: expiry,\r\n ...optionsData,\r\n }\r\n } catch {}\r\n\r\n return null\r\n}\r\n","import { TableAlign } from '../../components/Table'\r\nimport { SortableColumn } from '../../hooks/use-sort-data'\r\n\r\nexport enum OptionsQuery {\r\n Ticker = 't',\r\n Expiry = 'e',\r\n Strike = 's',\r\n Order = 'o',\r\n View = 'ov',\r\n Type = 'ty',\r\n}\r\n\r\nexport enum OptionsSubpage {\r\n Prices = 'oc',\r\n Volatility = 'ocv',\r\n}\r\n\r\nexport enum OptionsView {\r\n ChainByDate = 'chain_date',\r\n ChainByStrike = 'chain_strike',\r\n ListByDate = 'list_date',\r\n ListByStrike = 'list_strike',\r\n Plot = 'plot',\r\n}\r\n\r\nexport enum OptionType {\r\n Call = 'call',\r\n Put = 'put',\r\n}\r\n\r\nexport interface Option {\r\n type: OptionType\r\n ticker: string\r\n exDate: number\r\n strike: number\r\n openInterest: number\r\n averageVolume: number\r\n bidPrice: number\r\n askPrice: number\r\n lastClose: number\r\n lastChange: number\r\n lastSize: number\r\n lastVolume: number\r\n lastTime: string\r\n iv: number | null\r\n delta: number | null\r\n gamma: number | null\r\n theta: number | null\r\n vega: number | null\r\n rho: number | null\r\n}\r\n\r\nexport interface OptionRow {\r\n strike: number\r\n exDate: number\r\n call: Option | null\r\n put: Option | null\r\n}\r\n\r\nexport interface LoaderBase {\r\n ticker: string | null\r\n options: Option[]\r\n lastClose: number | null\r\n lastTime: number | null\r\n hasData?: boolean\r\n}\r\n\r\nexport interface OptionsByDateLoader extends LoaderBase {\r\n subpage: OptionsSubpage\r\n view: OptionsView.ChainByDate | OptionsView.ListByDate\r\n expiries: string[]\r\n currentExpiry: string\r\n}\r\n\r\nexport interface OptionsByStrikeLoader extends LoaderBase {\r\n subpage: OptionsSubpage\r\n view: OptionsView.ChainByStrike | OptionsView.ListByStrike\r\n strikes: number[]\r\n currentStrike: number\r\n}\r\n\r\nexport interface PlotLoader {\r\n subpage: OptionsSubpage\r\n view: OptionsView.Plot\r\n optionable: boolean\r\n options: Option[]\r\n}\r\n\r\nexport type OptionsLoaderData = OptionsByDateLoader | OptionsByStrikeLoader | PlotLoader\r\n\r\nexport enum ColumnId {\r\n ContractName = 'contractName',\r\n LastClose = 'lastClose',\r\n ChangeUsd = 'lastChange',\r\n ChangePct = 'changePct',\r\n BidPrice = 'bidPrice',\r\n AskPrice = 'askPrice',\r\n Volume = 'lastVolume',\r\n OpenInterest = 'openInterest',\r\n StrikePrice = 'strike',\r\n ExpirationDate = 'exDate',\r\n LastTrade = 'lastTime',\r\n IV = 'iv',\r\n Delta = 'delta',\r\n Gamma = 'gamma',\r\n Theta = 'theta',\r\n Vega = 'vega',\r\n Rho = 'rho',\r\n}\r\n\r\nexport enum RowKind {\r\n OptionRow, // Base row which includes both call and put. Used to render strike price\r\n Call,\r\n Put,\r\n}\r\n\r\ninterface OptionRowKind {\r\n ticker?: string\r\n lastClose?: number | null\r\n kind: RowKind.OptionRow\r\n row: OptionRow\r\n}\r\n\r\nexport interface CallKind {\r\n ticker?: string\r\n lastClose?: number | null\r\n kind: RowKind.Call\r\n row: Option\r\n}\r\n\r\ninterface PutKind {\r\n ticker?: string\r\n lastClose?: number | null\r\n kind: RowKind.Put\r\n row: Option\r\n}\r\n\r\nexport type ColumnRendererProps = CallKind | PutKind | OptionRowKind\r\n\r\nexport interface TableColumnDefinition extends SortableColumn {\r\n name: string\r\n align?: TableAlign\r\n className?: string\r\n renderColumn: (props: ColumnRendererProps) => React.ReactNode\r\n}\r\n\r\nexport type MappedSubpageOrders = { [key in OptionsSubpage]?: string }\r\n","import { formatDate } from '../../../../app/header/utils'\r\nimport { DATE_FORMAT_DB, DATE_FORMAT_INT, LINK_COLUMN_NAME } from '../constants/common'\r\nimport { ColumnId, MappedSubpageOrders, Option, OptionRow, OptionsQuery, OptionsSubpage, OptionsView } from '../types'\r\n\r\nconst DELIMITER = '|'\r\n\r\nfunction parseOrder(input: string | null): MappedSubpageOrders {\r\n if (!input) return {}\r\n const parts = input.split(DELIMITER)\r\n let pricesOrder, volatilityOrder\r\n if (parts.length === 1) pricesOrder = volatilityOrder = parts[0]\r\n else [pricesOrder, volatilityOrder] = parts\r\n return {\r\n [OptionsSubpage.Prices]: pricesOrder,\r\n [OptionsSubpage.Volatility]: volatilityOrder,\r\n }\r\n}\r\n\r\nexport function orderToString(obj: MappedSubpageOrders): string {\r\n const arr = [obj[OptionsSubpage.Prices], obj[OptionsSubpage.Volatility]]\r\n return arr.join(DELIMITER)\r\n}\r\n\r\nexport type OptionsParsedQuery = ReturnType\r\n\r\nexport function parseOptionsQuery(query: URLSearchParams) {\r\n const strike = Number(query.get(OptionsQuery.Strike))\r\n\r\n return {\r\n params: Object.fromEntries(query.entries()) as Record, // Re-export the original query as key/val\r\n ticker: query.get(OptionsQuery.Ticker)!, // Validated on BE\r\n expiry: query.get(OptionsQuery.Expiry),\r\n order: parseOrder(query.get(OptionsQuery.Order)),\r\n strike: Number.isFinite(strike) ? strike : null,\r\n view: (query.get(OptionsQuery.View) as OptionsView) ?? OptionsView.ChainByDate,\r\n type: query.get(OptionsQuery.Type) as OptionsSubpage,\r\n }\r\n}\r\n\r\nexport function evalLinkOrder(order: string, linkAlias: string) {\r\n if (!linkAlias) return order\r\n if (order === LINK_COLUMN_NAME) return linkAlias\r\n if (order === `-${LINK_COLUMN_NAME}`) return `-${linkAlias}`\r\n return order\r\n}\r\n\r\nexport function getViewLink(columnId: ColumnId, searchParams: URLSearchParams, option: Option | OptionRow) {\r\n const middleLink = new URLSearchParams(searchParams)\r\n\r\n switch (searchParams.get(OptionsQuery.View)) {\r\n case OptionsView.ChainByStrike:\r\n middleLink.set(OptionsQuery.View, OptionsView.ChainByDate)\r\n break\r\n case OptionsView.ListByDate:\r\n middleLink.set(OptionsQuery.View, OptionsView.ListByStrike)\r\n break\r\n case OptionsView.ListByStrike:\r\n middleLink.set(OptionsQuery.View, OptionsView.ListByDate)\r\n break\r\n case OptionsView.ChainByDate:\r\n default:\r\n middleLink.set(OptionsQuery.View, OptionsView.ChainByStrike)\r\n }\r\n\r\n if (columnId === ColumnId.ExpirationDate) {\r\n middleLink.delete(OptionsQuery.Strike)\r\n middleLink.set(OptionsQuery.Expiry, formatDate(option.exDate, DATE_FORMAT_INT, DATE_FORMAT_DB))\r\n } else {\r\n middleLink.delete(OptionsQuery.Expiry)\r\n middleLink.set(OptionsQuery.Strike, option.strike.toString())\r\n }\r\n\r\n return middleLink\r\n}\r\n"],"names":["getDate","seed","date","Date","dateAsNY","getUTCFullYear","getUTCMonth","getUTCDate","getUTCHours","getUTCMinutes","getUTCSeconds","isDst","dayNumber","monthIndex","getMonth","previousSunday","getDay","getIsDstInNy","setUTCHours","getWeekDay","toLocaleDateString","weekday","uppercase","arguments","length","undefined","name","month","toUpperCase","toString","padStart","getTime","toLocaleString","hour","minute","hour12","TimeFormat","getFormattedDateString","long","getFullYear","short","dateOnly","timeOnly","formatDate","value","inputOrOutputFormat","outputFormat","dateFns","isPremarket","isPremium","FinvizSettings","hasUserPremium","dayOfWeek","min","getMinutes","hours","getHours","isAftermarket","HOLIDAY_DATES","label","test","day","isHoliday","find","holiday","getHoliday","getEarningsDateSuffix","DATE_FORMAT_DB","DATE_FORMAT_INT","DATE_FORMAT_VIEW","DATE_FORMAT_VIEW_LONG","DATE_FORMAT_SCATTER_PLOT","LINK_COLUMN_NAME","OptionsView","ChainByDate","OptionsSubpage","Prices","optionsData","ticker","query","apiRequest","async","loader","args","url","URL","request","parsedQuery","parseOptionsQuery","searchParams","isDateView","ListByDate","includes","view","expiry","initialResponse","parseRouteInitData","removeElement","dateLoaderInit","expiries","set","OptionsQuery","Expiry","currentExpiry","replace","Plot","api","filterLastClose","subpage","type","plotDataLoader","ChainByStrike","ListByStrike","optionsByStrikeLoader","optionsByDateLoader","strikes","strike","currentStrike","OptionType","ColumnId","RowKind","DELIMITER","parseOrder","input","parts","split","pricesOrder","volatilityOrder","Volatility","orderToString","obj","join","_ref","Number","get","Strike","params","Object","fromEntries","entries","Ticker","order","Order","isFinite","View","Type","evalLinkOrder","linkAlias","getViewLink","columnId","option","middleLink","URLSearchParams","ExpirationDate","delete","exDate"],"sourceRoot":""}