{"version":3,"file":"options-loaders.dca3e507.js","mappings":"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","sources":["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":["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":["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","toString","Plot","api","filterLastClose","subpage","type","plotDataLoader","ChainByStrike","ListByStrike","optionsByStrikeLoader","optionsByDateLoader","strikes","strike","currentStrike","OptionType","ColumnId","RowKind","DELIMITER","parseOrder","input","parts","split","pricesOrder","volatilityOrder","length","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","formatDate","exDate"],"sourceRoot":""}