fin-ratios 0.7.3 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +779 -0
- package/dist/fetchers/alphavantage/index.cjs +0 -2
- package/dist/fetchers/alphavantage/index.js +0 -2
- package/dist/fetchers/edgar/index.cjs +0 -2
- package/dist/fetchers/edgar/index.js +0 -2
- package/dist/fetchers/fmp/index.cjs +0 -2
- package/dist/fetchers/fmp/index.js +0 -2
- package/dist/fetchers/polygon/index.cjs +174 -0
- package/dist/fetchers/polygon/index.d.cts +84 -0
- package/dist/fetchers/polygon/index.d.ts +84 -0
- package/dist/fetchers/polygon/index.js +171 -0
- package/dist/fetchers/yahoo/index.cjs +0 -2
- package/dist/fetchers/yahoo/index.js +0 -2
- package/dist/hooks/index.cjs +0 -2
- package/dist/hooks/index.js +0 -2
- package/dist/index.cjs +557 -8
- package/dist/index.d.cts +289 -1
- package/dist/index.d.ts +289 -1
- package/dist/index.js +553 -9
- package/package.json +11 -3
- package/dist/fetchers/alphavantage/index.cjs.map +0 -1
- package/dist/fetchers/alphavantage/index.js.map +0 -1
- package/dist/fetchers/edgar/index.cjs.map +0 -1
- package/dist/fetchers/edgar/index.js.map +0 -1
- package/dist/fetchers/fmp/index.cjs.map +0 -1
- package/dist/fetchers/fmp/index.js.map +0 -1
- package/dist/fetchers/yahoo/index.cjs.map +0 -1
- package/dist/fetchers/yahoo/index.js.map +0 -1
- package/dist/hooks/index.cjs.map +0 -1
- package/dist/hooks/index.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/fetchers/alphavantage/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Alpha Vantage fetcher for fin-ratios (TypeScript).\n *\n * Free tier: 25 requests/day. Premium: higher limits.\n * Get a free API key at https://www.alphavantage.co/support/#api-key\n *\n * @example\n * import { fetchAlphaVantage } from 'fin-ratios/fetchers/alphavantage'\n * const data = await fetchAlphaVantage('IBM', { apiKey: 'your_key' })\n * console.log(data.income.revenue)\n */\n\nimport type { IncomeStatement, BalanceSheet, CashFlowStatement, MarketData } from '../../types/index.js'\n\nconst BASE = 'https://www.alphavantage.co/query'\n\nexport interface AlphaVantageOptions {\n apiKey: string\n periods?: number\n quarterly?: boolean\n}\n\nexport interface AlphaVantagePeriodData {\n period: string\n income: IncomeStatement\n balance: BalanceSheet\n cashFlow: CashFlowStatement\n marketData: MarketData\n}\n\n/**\n * Fetch financial statements from Alpha Vantage for a given ticker.\n */\nexport async function fetchAlphaVantage(\n ticker: string,\n options: AlphaVantageOptions\n): Promise<AlphaVantagePeriodData[]> {\n const { apiKey, periods = 4, quarterly = false } = options\n\n const freq = quarterly ? 'quarterlyReports' : 'annualReports'\n\n const [incData, balData, cfData, quoteData] = await Promise.all([\n _get({ function: 'INCOME_STATEMENT', symbol: ticker, apikey: apiKey }),\n _get({ function: 'BALANCE_SHEET', symbol: ticker, apikey: apiKey }),\n _get({ function: 'CASH_FLOW', symbol: ticker, apikey: apiKey }),\n _get({ function: 'GLOBAL_QUOTE', symbol: ticker, apikey: apiKey }),\n ]) as any[]\n\n const incReports: any[] = (incData[freq] ?? []).slice(0, periods)\n const balReports: any[] = (balData[freq] ?? []).slice(0, periods)\n const cfReports: any[] = (cfData[freq] ?? []).slice(0, periods)\n const quote = quoteData['Global Quote'] ?? {}\n\n const price = _n(quote['05. price'])\n const results: AlphaVantagePeriodData[] = []\n\n for (let i = 0; i < incReports.length; i++) {\n const inc = incReports[i] ?? {}\n const bal = balReports[i] ?? {}\n const cf = cfReports[i] ?? {}\n\n results.push({\n period: inc.fiscalDateEnding ?? '',\n income: {\n revenue: _n(inc.totalRevenue),\n grossProfit: _n(inc.grossProfit),\n cogs: _n(inc.costOfRevenue),\n ebit: _n(inc.ebit),\n ebitda: _n(inc.ebitda),\n netIncome: _n(inc.netIncome),\n interestExpense: Math.abs(_n(inc.interestExpense)),\n incomeTaxExpense: _n(inc.incomeTaxExpense),\n ebt: _n(inc.incomeBeforeTax),\n depreciationAndAmortization:_n(inc.depreciationAndAmortization),\n sharesOutstanding: _n(inc.commonStockSharesOutstanding),\n eps: 0,\n },\n balance: {\n totalAssets: _n(bal.totalAssets),\n currentAssets: _n(bal.totalCurrentAssets),\n cash: _n(bal.cashAndCashEquivalentsAtCarryingValue),\n accountsReceivable: _n(bal.currentNetReceivables),\n inventory: _n(bal.inventory),\n netPPE: _n(bal.propertyPlantEquipmentNet),\n goodwill: _n(bal.goodwill),\n retainedEarnings: _n(bal.retainedEarnings),\n totalLiabilities: _n(bal.totalLiabilities),\n currentLiabilities: _n(bal.totalCurrentLiabilities),\n accountsPayable: _n(bal.currentAccountsPayable),\n longTermDebt: _n(bal.longTermDebtNoncurrent),\n totalDebt: _n(bal.shortLongTermDebtTotal),\n totalEquity: _n(bal.totalShareholderEquity),\n sharesOutstanding: _n(bal.commonStockSharesOutstanding),\n },\n cashFlow: {\n operatingCashFlow: _n(cf.operatingCashflow),\n capex: Math.abs(_n(cf.capitalExpenditures)),\n investingCashFlow: _n(cf.cashflowFromInvestment),\n financingCashFlow: _n(cf.cashflowFromFinancing),\n dividendsPaid: _n(cf.dividendPayout),\n },\n marketData: {\n price,\n marketCap: 0, // not returned by Alpha Vantage income statement endpoints\n sharesOutstanding: _n(inc.commonStockSharesOutstanding),\n ticker,\n },\n })\n }\n\n return results\n}\n\nasync function _get(params: Record<string, string>): Promise<unknown> {\n const query = new URLSearchParams(params)\n const resp = await fetch(`${BASE}?${query}`)\n if (!resp.ok) throw new Error(`Alpha Vantage request failed: ${resp.status}`)\n return resp.json()\n}\n\nfunction _n(v: unknown): number {\n if (v == null || v === 'None' || v === '-') return 0\n const n = Number(v)\n return isNaN(n) ? 0 : n\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/fetchers/edgar/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * SEC EDGAR fetcher for fin-ratios (TypeScript).\n *\n * Fetches financial data from the free SEC EDGAR XBRL API.\n * No API key required. US companies only.\n *\n * Rate limit: ~10 requests/second (SEC guidelines). Add delays for bulk use.\n *\n * @example\n * import { fetchEdgar, fetchEdgarNormalized } from 'fin-ratios/fetchers/edgar'\n *\n * // Structured filings (newest-first)\n * const filings = await fetchEdgar('AAPL', { numYears: 5 })\n *\n * // Flat records ready for scoring utilities (oldest-first)\n * const annualData = await fetchEdgarNormalized('AAPL', { numYears: 10 })\n * const quality = qualityScore(annualData)\n */\n\nimport type { IncomeStatement, BalanceSheet, CashFlowStatement } from '../../types/index.js'\nimport type { AnnualQualityData } from '../../utils/quality-score.js'\nimport type { AnnualCapitalData } from '../../utils/capital-allocation.js'\n\nconst COMPANY_TICKERS_URL = 'https://data.sec.gov/files/company_tickers.json'\nconst EDGAR_BASE = 'https://data.sec.gov/api/xbrl/companyfacts'\n\nconst HEADERS = {\n 'User-Agent': 'fin-ratios/1.0 contact@fin-ratios.dev',\n 'Accept-Encoding': 'gzip, deflate',\n}\n\nexport interface EdgarOptions {\n numYears?: number\n}\n\nexport interface EdgarFilingData {\n fiscalYear: string\n income: IncomeStatement\n balance: BalanceSheet\n cashFlow: CashFlowStatement & { dividendsPaid: number }\n}\n\n/**\n * Normalised annual record that satisfies all scoring utility input types:\n * moatScore, capitalAllocationScore, earningsQualityScore, qualityScore.\n */\nexport type EdgarAnnualRecord = AnnualQualityData &\n AnnualCapitalData & {\n year: string\n sharesOutstanding?: number\n currentAssets?: number\n currentLiabilities?: number\n }\n\n/**\n * Fetch multi-year annual filings from SEC EDGAR for a US stock ticker.\n * Returns newest-first.\n */\nexport async function fetchEdgar(\n ticker: string,\n options: EdgarOptions = {}\n): Promise<EdgarFilingData[]> {\n const { numYears = 5 } = options\n\n // Resolve ticker → CIK\n const tickerMap = (await _get(COMPANY_TICKERS_URL)) as Record<\n string,\n { cik_str: number; ticker: string; title: string }\n >\n const entry = Object.values(tickerMap).find(\n v => v.ticker.toUpperCase() === ticker.toUpperCase()\n )\n if (!entry) throw new Error(`EDGAR: ticker ${ticker} not found`)\n\n const cik = String(entry.cik_str).padStart(10, '0')\n const facts = (await _get(`${EDGAR_BASE}/CIK${cik}.json`)) as {\n facts: {\n 'us-gaap'?: Record<\n string,\n {\n units: {\n USD?: { val: number; end: string; form: string; fp: string }[]\n shares?: { val: number; end: string; form: string; fp: string }[]\n }\n }\n >\n }\n }\n\n const gaap = facts.facts['us-gaap'] ?? {}\n\n function _annual(concept: string): { end: string; val: number }[] {\n return (gaap[concept]?.units?.USD ?? [])\n .filter(e => e.form === '10-K')\n .sort((a, b) => b.end.localeCompare(a.end))\n }\n\n function _annualShares(concept: string): { end: string; val: number }[] {\n return (gaap[concept]?.units?.shares ?? [])\n .filter(e => e.form === '10-K')\n .sort((a, b) => b.end.localeCompare(a.end))\n }\n\n function _pick(concept: string, year: string): number {\n return _annual(concept).find(e => e.end.startsWith(year))?.val ?? 0\n }\n\n function _pickShares(concept: string, year: string): number {\n return _annualShares(concept).find(e => e.end.startsWith(year))?.val ?? 0\n }\n\n // Determine available fiscal years from revenue\n const revEntries = _annual('Revenues').concat(\n _annual('RevenueFromContractWithCustomerExcludingAssessedTax')\n )\n const years = [...new Set(revEntries.map(e => e.end.slice(0, 4)))].slice(0, numYears)\n\n return years.map(year => {\n const rev = _pick('Revenues', year) || _pick('RevenueFromContractWithCustomerExcludingAssessedTax', year)\n const gp = _pick('GrossProfit', year)\n const ebit = _pick('OperatingIncomeLoss', year)\n const ni = _pick('NetIncomeLoss', year)\n const tax = _pick('IncomeTaxExpenseBenefit', year) || _pick('IncomeTaxesPaidNet', year)\n const int_ = _pick('InterestExpense', year) || _pick('InterestAndDebtExpense', year)\n const depr = _pick('DepreciationDepletionAndAmortization', year) || _pick('DepreciationAndAmortization', year)\n const ta = _pick('Assets', year)\n const ca = _pick('AssetsCurrent', year)\n const cash = _pick('CashAndCashEquivalentsAtCarryingValue', year) || _pick('CashCashEquivalentsAndShortTermInvestments', year)\n const ar = _pick('AccountsReceivableNetCurrent', year)\n const inv = _pick('InventoryNet', year)\n const cl = _pick('LiabilitiesCurrent', year)\n const tl = _pick('Liabilities', year)\n const ltd = _pick('LongTermDebt', year) || _pick('LongTermDebtNoncurrent', year)\n const std = _pick('ShortTermBorrowings', year) || _pick('DebtCurrent', year)\n const re = _pick('RetainedEarningsAccumulatedDeficit', year)\n const te = _pick('StockholdersEquity', year) || _pick('StockholdersEquityIncludingPortionAttributableToNoncontrollingInterest', year)\n const ocf = _pick('NetCashProvidedByUsedInOperatingActivities', year)\n const capex = _pick('PaymentsToAcquirePropertyPlantAndEquipment', year)\n const divs = _pick('PaymentsOfDividends', year) || _pick('PaymentsOfDividendsCommonStock', year)\n const shs = _pickShares('CommonStockSharesOutstanding', year) || _pickShares('CommonStockSharesIssued', year)\n\n const totalDebt = ltd + std\n const ebt = ni + tax\n\n return {\n fiscalYear: year,\n income: {\n revenue: rev, grossProfit: gp, cogs: rev - gp,\n ebit, ebitda: ebit + depr, netIncome: ni,\n interestExpense: Math.abs(int_), incomeTaxExpense: tax, ebt,\n depreciationAndAmortization: depr,\n sharesOutstanding: shs, eps: shs > 0 ? ni / shs : 0,\n },\n balance: {\n totalAssets: ta, currentAssets: ca, cash, accountsReceivable: ar,\n inventory: inv, netPPE: 0, goodwill: 0,\n retainedEarnings: re, totalLiabilities: tl, currentLiabilities: cl,\n accountsPayable: _pick('AccountsPayableCurrent', year),\n longTermDebt: ltd, totalDebt,\n totalEquity: te, sharesOutstanding: shs,\n },\n cashFlow: {\n operatingCashFlow: ocf, capex: Math.abs(capex),\n investingCashFlow: 0, financingCashFlow: 0,\n dividendsPaid: Math.abs(divs),\n },\n }\n })\n}\n\n/**\n * Flatten EDGAR filings into a list of normalised annual records, oldest-first.\n * The returned type satisfies all scoring utility inputs:\n * moatScore, capitalAllocationScore, earningsQualityScore, qualityScore.\n */\nexport function normalizeForScoring(filings: EdgarFilingData[]): EdgarAnnualRecord[] {\n return [...filings].reverse().map(f => {\n const rec: EdgarAnnualRecord = {\n year: f.fiscalYear,\n revenue: f.income.revenue,\n grossProfit: f.income.grossProfit,\n ebit: f.income.ebit,\n ebt: f.income.ebt,\n netIncome: f.income.netIncome,\n incomeTaxExpense: f.income.incomeTaxExpense,\n interestExpense: f.income.interestExpense,\n totalAssets: f.balance.totalAssets,\n totalEquity: f.balance.totalEquity,\n totalDebt: f.balance.totalDebt,\n cash: f.balance.cash,\n currentAssets: f.balance.currentAssets,\n currentLiabilities: f.balance.currentLiabilities,\n capex: f.cashFlow.capex,\n depreciation: f.income.depreciationAndAmortization,\n operatingCashFlow: f.cashFlow.operatingCashFlow,\n accountsReceivable: f.balance.accountsReceivable,\n }\n rec.dividendsPaid = f.cashFlow.dividendsPaid\n if (f.balance.sharesOutstanding) rec.sharesOutstanding = f.balance.sharesOutstanding\n return rec\n })\n}\n\n/**\n * @deprecated Use `normalizeForScoring` instead.\n * Kept for backwards compatibility.\n */\nexport function flattenEdgarData(filings: EdgarFilingData[]): EdgarAnnualRecord[] {\n return normalizeForScoring(filings)\n}\n\n/**\n * Fetch EDGAR data and return normalised annual records (oldest-first),\n * ready to pass directly to qualityScore(), moatScore(), etc.\n *\n * @example\n * const annualData = await fetchEdgarNormalized('AAPL', { numYears: 10 })\n * const qs = qualityScore(annualData)\n */\nexport async function fetchEdgarNormalized(\n ticker: string,\n options: EdgarOptions = {},\n): Promise<EdgarAnnualRecord[]> {\n return normalizeForScoring(await fetchEdgar(ticker, options))\n}\n\n/**\n * @deprecated Use `fetchEdgarNormalized` instead.\n */\nexport async function fetchEdgarFlat(\n ticker: string,\n options: EdgarOptions = {},\n): Promise<EdgarAnnualRecord[]> {\n return fetchEdgarNormalized(ticker, options)\n}\n\nasync function _get(url: string): Promise<unknown> {\n const resp = await fetch(url, { headers: HEADERS })\n if (!resp.ok) throw new Error(`EDGAR fetch failed: ${resp.status} ${url}`)\n return resp.json()\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/fetchers/edgar/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * SEC EDGAR fetcher for fin-ratios (TypeScript).\n *\n * Fetches financial data from the free SEC EDGAR XBRL API.\n * No API key required. US companies only.\n *\n * Rate limit: ~10 requests/second (SEC guidelines). Add delays for bulk use.\n *\n * @example\n * import { fetchEdgar, fetchEdgarNormalized } from 'fin-ratios/fetchers/edgar'\n *\n * // Structured filings (newest-first)\n * const filings = await fetchEdgar('AAPL', { numYears: 5 })\n *\n * // Flat records ready for scoring utilities (oldest-first)\n * const annualData = await fetchEdgarNormalized('AAPL', { numYears: 10 })\n * const quality = qualityScore(annualData)\n */\n\nimport type { IncomeStatement, BalanceSheet, CashFlowStatement } from '../../types/index.js'\nimport type { AnnualQualityData } from '../../utils/quality-score.js'\nimport type { AnnualCapitalData } from '../../utils/capital-allocation.js'\n\nconst COMPANY_TICKERS_URL = 'https://data.sec.gov/files/company_tickers.json'\nconst EDGAR_BASE = 'https://data.sec.gov/api/xbrl/companyfacts'\n\nconst HEADERS = {\n 'User-Agent': 'fin-ratios/1.0 contact@fin-ratios.dev',\n 'Accept-Encoding': 'gzip, deflate',\n}\n\nexport interface EdgarOptions {\n numYears?: number\n}\n\nexport interface EdgarFilingData {\n fiscalYear: string\n income: IncomeStatement\n balance: BalanceSheet\n cashFlow: CashFlowStatement & { dividendsPaid: number }\n}\n\n/**\n * Normalised annual record that satisfies all scoring utility input types:\n * moatScore, capitalAllocationScore, earningsQualityScore, qualityScore.\n */\nexport type EdgarAnnualRecord = AnnualQualityData &\n AnnualCapitalData & {\n year: string\n sharesOutstanding?: number\n currentAssets?: number\n currentLiabilities?: number\n }\n\n/**\n * Fetch multi-year annual filings from SEC EDGAR for a US stock ticker.\n * Returns newest-first.\n */\nexport async function fetchEdgar(\n ticker: string,\n options: EdgarOptions = {}\n): Promise<EdgarFilingData[]> {\n const { numYears = 5 } = options\n\n // Resolve ticker → CIK\n const tickerMap = (await _get(COMPANY_TICKERS_URL)) as Record<\n string,\n { cik_str: number; ticker: string; title: string }\n >\n const entry = Object.values(tickerMap).find(\n v => v.ticker.toUpperCase() === ticker.toUpperCase()\n )\n if (!entry) throw new Error(`EDGAR: ticker ${ticker} not found`)\n\n const cik = String(entry.cik_str).padStart(10, '0')\n const facts = (await _get(`${EDGAR_BASE}/CIK${cik}.json`)) as {\n facts: {\n 'us-gaap'?: Record<\n string,\n {\n units: {\n USD?: { val: number; end: string; form: string; fp: string }[]\n shares?: { val: number; end: string; form: string; fp: string }[]\n }\n }\n >\n }\n }\n\n const gaap = facts.facts['us-gaap'] ?? {}\n\n function _annual(concept: string): { end: string; val: number }[] {\n return (gaap[concept]?.units?.USD ?? [])\n .filter(e => e.form === '10-K')\n .sort((a, b) => b.end.localeCompare(a.end))\n }\n\n function _annualShares(concept: string): { end: string; val: number }[] {\n return (gaap[concept]?.units?.shares ?? [])\n .filter(e => e.form === '10-K')\n .sort((a, b) => b.end.localeCompare(a.end))\n }\n\n function _pick(concept: string, year: string): number {\n return _annual(concept).find(e => e.end.startsWith(year))?.val ?? 0\n }\n\n function _pickShares(concept: string, year: string): number {\n return _annualShares(concept).find(e => e.end.startsWith(year))?.val ?? 0\n }\n\n // Determine available fiscal years from revenue\n const revEntries = _annual('Revenues').concat(\n _annual('RevenueFromContractWithCustomerExcludingAssessedTax')\n )\n const years = [...new Set(revEntries.map(e => e.end.slice(0, 4)))].slice(0, numYears)\n\n return years.map(year => {\n const rev = _pick('Revenues', year) || _pick('RevenueFromContractWithCustomerExcludingAssessedTax', year)\n const gp = _pick('GrossProfit', year)\n const ebit = _pick('OperatingIncomeLoss', year)\n const ni = _pick('NetIncomeLoss', year)\n const tax = _pick('IncomeTaxExpenseBenefit', year) || _pick('IncomeTaxesPaidNet', year)\n const int_ = _pick('InterestExpense', year) || _pick('InterestAndDebtExpense', year)\n const depr = _pick('DepreciationDepletionAndAmortization', year) || _pick('DepreciationAndAmortization', year)\n const ta = _pick('Assets', year)\n const ca = _pick('AssetsCurrent', year)\n const cash = _pick('CashAndCashEquivalentsAtCarryingValue', year) || _pick('CashCashEquivalentsAndShortTermInvestments', year)\n const ar = _pick('AccountsReceivableNetCurrent', year)\n const inv = _pick('InventoryNet', year)\n const cl = _pick('LiabilitiesCurrent', year)\n const tl = _pick('Liabilities', year)\n const ltd = _pick('LongTermDebt', year) || _pick('LongTermDebtNoncurrent', year)\n const std = _pick('ShortTermBorrowings', year) || _pick('DebtCurrent', year)\n const re = _pick('RetainedEarningsAccumulatedDeficit', year)\n const te = _pick('StockholdersEquity', year) || _pick('StockholdersEquityIncludingPortionAttributableToNoncontrollingInterest', year)\n const ocf = _pick('NetCashProvidedByUsedInOperatingActivities', year)\n const capex = _pick('PaymentsToAcquirePropertyPlantAndEquipment', year)\n const divs = _pick('PaymentsOfDividends', year) || _pick('PaymentsOfDividendsCommonStock', year)\n const shs = _pickShares('CommonStockSharesOutstanding', year) || _pickShares('CommonStockSharesIssued', year)\n\n const totalDebt = ltd + std\n const ebt = ni + tax\n\n return {\n fiscalYear: year,\n income: {\n revenue: rev, grossProfit: gp, cogs: rev - gp,\n ebit, ebitda: ebit + depr, netIncome: ni,\n interestExpense: Math.abs(int_), incomeTaxExpense: tax, ebt,\n depreciationAndAmortization: depr,\n sharesOutstanding: shs, eps: shs > 0 ? ni / shs : 0,\n },\n balance: {\n totalAssets: ta, currentAssets: ca, cash, accountsReceivable: ar,\n inventory: inv, netPPE: 0, goodwill: 0,\n retainedEarnings: re, totalLiabilities: tl, currentLiabilities: cl,\n accountsPayable: _pick('AccountsPayableCurrent', year),\n longTermDebt: ltd, totalDebt,\n totalEquity: te, sharesOutstanding: shs,\n },\n cashFlow: {\n operatingCashFlow: ocf, capex: Math.abs(capex),\n investingCashFlow: 0, financingCashFlow: 0,\n dividendsPaid: Math.abs(divs),\n },\n }\n })\n}\n\n/**\n * Flatten EDGAR filings into a list of normalised annual records, oldest-first.\n * The returned type satisfies all scoring utility inputs:\n * moatScore, capitalAllocationScore, earningsQualityScore, qualityScore.\n */\nexport function normalizeForScoring(filings: EdgarFilingData[]): EdgarAnnualRecord[] {\n return [...filings].reverse().map(f => {\n const rec: EdgarAnnualRecord = {\n year: f.fiscalYear,\n revenue: f.income.revenue,\n grossProfit: f.income.grossProfit,\n ebit: f.income.ebit,\n ebt: f.income.ebt,\n netIncome: f.income.netIncome,\n incomeTaxExpense: f.income.incomeTaxExpense,\n interestExpense: f.income.interestExpense,\n totalAssets: f.balance.totalAssets,\n totalEquity: f.balance.totalEquity,\n totalDebt: f.balance.totalDebt,\n cash: f.balance.cash,\n currentAssets: f.balance.currentAssets,\n currentLiabilities: f.balance.currentLiabilities,\n capex: f.cashFlow.capex,\n depreciation: f.income.depreciationAndAmortization,\n operatingCashFlow: f.cashFlow.operatingCashFlow,\n accountsReceivable: f.balance.accountsReceivable,\n }\n rec.dividendsPaid = f.cashFlow.dividendsPaid\n if (f.balance.sharesOutstanding) rec.sharesOutstanding = f.balance.sharesOutstanding\n return rec\n })\n}\n\n/**\n * @deprecated Use `normalizeForScoring` instead.\n * Kept for backwards compatibility.\n */\nexport function flattenEdgarData(filings: EdgarFilingData[]): EdgarAnnualRecord[] {\n return normalizeForScoring(filings)\n}\n\n/**\n * Fetch EDGAR data and return normalised annual records (oldest-first),\n * ready to pass directly to qualityScore(), moatScore(), etc.\n *\n * @example\n * const annualData = await fetchEdgarNormalized('AAPL', { numYears: 10 })\n * const qs = qualityScore(annualData)\n */\nexport async function fetchEdgarNormalized(\n ticker: string,\n options: EdgarOptions = {},\n): Promise<EdgarAnnualRecord[]> {\n return normalizeForScoring(await fetchEdgar(ticker, options))\n}\n\n/**\n * @deprecated Use `fetchEdgarNormalized` instead.\n */\nexport async function fetchEdgarFlat(\n ticker: string,\n options: EdgarOptions = {},\n): Promise<EdgarAnnualRecord[]> {\n return fetchEdgarNormalized(ticker, options)\n}\n\nasync function _get(url: string): Promise<unknown> {\n const resp = await fetch(url, { headers: HEADERS })\n if (!resp.ok) throw new Error(`EDGAR fetch failed: ${resp.status} ${url}`)\n return resp.json()\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/fetchers/fmp/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Financial Modeling Prep (FMP) fetcher.\n * Free tier: 250 requests/day.\n * Get API key: https://financialmodelingprep.com/developer/docs\n */\n\nimport type {\n IncomeStatement,\n BalanceSheet,\n CashFlowStatement,\n MarketData,\n} from '../../types/index.js'\n\nconst FMP_BASE = 'https://financialmodelingprep.com/api/v3'\n\nexport interface FmpOptions {\n apiKey: string\n periods?: number\n quarterly?: boolean\n}\n\nexport interface FmpPeriodData {\n period: string\n income: IncomeStatement\n balance: BalanceSheet\n cashFlow: CashFlowStatement\n marketData: MarketData\n ratios?: Record<string, number | null>\n}\n\n/**\n * Fetch financial statements from Financial Modeling Prep.\n *\n * @example\n * const data = await fetchFmp('AAPL', { apiKey: 'your_key', periods: 4 })\n * for (const period of data) {\n * const roicVal = roic({ nopat: ..., investedCapital: ... })\n * }\n */\nexport async function fetchFmp(\n ticker: string,\n options: FmpOptions\n): Promise<FmpPeriodData[]> {\n const { apiKey, periods = 4, quarterly = false } = options\n const period = quarterly ? 'quarter' : 'annual'\n const limit = periods\n\n const [incData, balData, cfData, ratioData, profileData] = await Promise.all([\n _get(`${FMP_BASE}/income-statement/${ticker}`, apiKey, { period, limit }),\n _get(`${FMP_BASE}/balance-sheet-statement/${ticker}`, apiKey, { period, limit }),\n _get(`${FMP_BASE}/cash-flow-statement/${ticker}`, apiKey, { period, limit }),\n _get(`${FMP_BASE}/ratios/${ticker}`, apiKey, { period, limit }),\n _get(`${FMP_BASE}/profile/${ticker}`, apiKey, {}),\n ])\n\n const profile = (profileData as any[])[0] ?? {}\n const results: FmpPeriodData[] = []\n\n for (let i = 0; i < Math.min(limit, (incData as any[]).length); i++) {\n const inc = (incData as any[])[i] ?? {}\n const bal = (balData as any[])[i] ?? {}\n const cf = (cfData as any[])[i] ?? {}\n const rat = (ratioData as any[])[i] ?? {}\n\n results.push({\n period: inc.date ?? '',\n income: {\n revenue: _n(inc.revenue),\n grossProfit: _n(inc.grossProfit),\n cogs: _n(inc.costOfRevenue),\n ebit: _n(inc.operatingIncome),\n ebitda: _n(inc.ebitda),\n netIncome: _n(inc.netIncome),\n interestExpense: Math.abs(_n(inc.interestExpense)),\n incomeTaxExpense: _n(inc.incomeTaxExpense),\n ebt: _n(inc.incomeBeforeTax),\n depreciationAndAmortization: _n(inc.depreciationAndAmortization),\n sharesOutstanding: _n(inc.weightedAverageShsOut),\n eps: _n(inc.eps),\n epsDiluted: _n(inc.epsdiluted),\n },\n balance: {\n totalAssets: _n(bal.totalAssets),\n currentAssets: _n(bal.totalCurrentAssets),\n cash: _n(bal.cashAndCashEquivalents),\n accountsReceivable: _n(bal.netReceivables),\n inventory: _n(bal.inventory),\n netPPE: _n(bal.propertyPlantEquipmentNet),\n goodwill: _n(bal.goodwill),\n intangibleAssets: _n(bal.intangibleAssets),\n retainedEarnings: _n(bal.retainedEarnings),\n totalLiabilities: _n(bal.totalLiabilities),\n currentLiabilities: _n(bal.totalCurrentLiabilities),\n accountsPayable: _n(bal.accountPayables),\n longTermDebt: _n(bal.longTermDebt),\n totalDebt: _n(bal.totalDebt),\n totalEquity: _n(bal.totalStockholdersEquity),\n sharesOutstanding: _n(inc.weightedAverageShsOut),\n },\n cashFlow: {\n operatingCashFlow: _n(cf.operatingCashFlow),\n capex: Math.abs(_n(cf.capitalExpenditure)),\n investingCashFlow: _n(cf.investingActivitiesCashFlow),\n financingCashFlow: _n(cf.financingActivitiesCashFlow),\n dividendsPaid: _n(cf.commonDividendsPaid),\n stockBasedCompensation: _n(cf.stockBasedCompensation),\n debtRepayments: _n(cf.debtRepayment),\n },\n marketData: {\n price: _n(profile.price),\n marketCap: _n(profile.mktCap),\n sharesOutstanding: _n(inc.weightedAverageShsOut),\n ticker,\n },\n ratios: {\n peRatio: _n(rat.priceEarningsRatio),\n pbRatio: _n(rat.priceToBookRatio),\n psRatio: _n(rat.priceToSalesRatio),\n evToEbitda: _n(rat.enterpriseValueMultiple),\n roic: _n(rat.returnOnCapitalEmployed),\n roe: _n(rat.returnOnEquity),\n roa: _n(rat.returnOnAssets),\n currentRatio: _n(rat.currentRatio),\n debtToEquity: _n(rat.debtEquityRatio),\n grossMargin: _n(rat.grossProfitMargin),\n operatingMargin: _n(rat.operatingProfitMargin),\n netMargin: _n(rat.netProfitMargin),\n },\n })\n }\n\n return results\n}\n\n/** Fetch the current S&P 500 constituent list. */\nexport async function fetchFmpSp500(apiKey: string): Promise<string[]> {\n const data = (await _get(`${FMP_BASE}/sp500_constituent`, apiKey, {})) as any[]\n return data.map(d => d.symbol).filter(Boolean)\n}\n\nasync function _get(url: string, apiKey: string, params: Record<string, unknown>): Promise<unknown> {\n const query = new URLSearchParams({ ...Object.fromEntries(Object.entries(params).map(([k, v]) => [k, String(v)])), apikey: apiKey })\n const resp = await fetch(`${url}?${query}`)\n if (!resp.ok) throw new Error(`FMP request failed: ${resp.status} ${url}`)\n return resp.json()\n}\n\nfunction _n(v: unknown): number {\n if (v == null) return 0\n const n = Number(v)\n return isNaN(n) ? 0 : n\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/fetchers/fmp/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Financial Modeling Prep (FMP) fetcher.\n * Free tier: 250 requests/day.\n * Get API key: https://financialmodelingprep.com/developer/docs\n */\n\nimport type {\n IncomeStatement,\n BalanceSheet,\n CashFlowStatement,\n MarketData,\n} from '../../types/index.js'\n\nconst FMP_BASE = 'https://financialmodelingprep.com/api/v3'\n\nexport interface FmpOptions {\n apiKey: string\n periods?: number\n quarterly?: boolean\n}\n\nexport interface FmpPeriodData {\n period: string\n income: IncomeStatement\n balance: BalanceSheet\n cashFlow: CashFlowStatement\n marketData: MarketData\n ratios?: Record<string, number | null>\n}\n\n/**\n * Fetch financial statements from Financial Modeling Prep.\n *\n * @example\n * const data = await fetchFmp('AAPL', { apiKey: 'your_key', periods: 4 })\n * for (const period of data) {\n * const roicVal = roic({ nopat: ..., investedCapital: ... })\n * }\n */\nexport async function fetchFmp(\n ticker: string,\n options: FmpOptions\n): Promise<FmpPeriodData[]> {\n const { apiKey, periods = 4, quarterly = false } = options\n const period = quarterly ? 'quarter' : 'annual'\n const limit = periods\n\n const [incData, balData, cfData, ratioData, profileData] = await Promise.all([\n _get(`${FMP_BASE}/income-statement/${ticker}`, apiKey, { period, limit }),\n _get(`${FMP_BASE}/balance-sheet-statement/${ticker}`, apiKey, { period, limit }),\n _get(`${FMP_BASE}/cash-flow-statement/${ticker}`, apiKey, { period, limit }),\n _get(`${FMP_BASE}/ratios/${ticker}`, apiKey, { period, limit }),\n _get(`${FMP_BASE}/profile/${ticker}`, apiKey, {}),\n ])\n\n const profile = (profileData as any[])[0] ?? {}\n const results: FmpPeriodData[] = []\n\n for (let i = 0; i < Math.min(limit, (incData as any[]).length); i++) {\n const inc = (incData as any[])[i] ?? {}\n const bal = (balData as any[])[i] ?? {}\n const cf = (cfData as any[])[i] ?? {}\n const rat = (ratioData as any[])[i] ?? {}\n\n results.push({\n period: inc.date ?? '',\n income: {\n revenue: _n(inc.revenue),\n grossProfit: _n(inc.grossProfit),\n cogs: _n(inc.costOfRevenue),\n ebit: _n(inc.operatingIncome),\n ebitda: _n(inc.ebitda),\n netIncome: _n(inc.netIncome),\n interestExpense: Math.abs(_n(inc.interestExpense)),\n incomeTaxExpense: _n(inc.incomeTaxExpense),\n ebt: _n(inc.incomeBeforeTax),\n depreciationAndAmortization: _n(inc.depreciationAndAmortization),\n sharesOutstanding: _n(inc.weightedAverageShsOut),\n eps: _n(inc.eps),\n epsDiluted: _n(inc.epsdiluted),\n },\n balance: {\n totalAssets: _n(bal.totalAssets),\n currentAssets: _n(bal.totalCurrentAssets),\n cash: _n(bal.cashAndCashEquivalents),\n accountsReceivable: _n(bal.netReceivables),\n inventory: _n(bal.inventory),\n netPPE: _n(bal.propertyPlantEquipmentNet),\n goodwill: _n(bal.goodwill),\n intangibleAssets: _n(bal.intangibleAssets),\n retainedEarnings: _n(bal.retainedEarnings),\n totalLiabilities: _n(bal.totalLiabilities),\n currentLiabilities: _n(bal.totalCurrentLiabilities),\n accountsPayable: _n(bal.accountPayables),\n longTermDebt: _n(bal.longTermDebt),\n totalDebt: _n(bal.totalDebt),\n totalEquity: _n(bal.totalStockholdersEquity),\n sharesOutstanding: _n(inc.weightedAverageShsOut),\n },\n cashFlow: {\n operatingCashFlow: _n(cf.operatingCashFlow),\n capex: Math.abs(_n(cf.capitalExpenditure)),\n investingCashFlow: _n(cf.investingActivitiesCashFlow),\n financingCashFlow: _n(cf.financingActivitiesCashFlow),\n dividendsPaid: _n(cf.commonDividendsPaid),\n stockBasedCompensation: _n(cf.stockBasedCompensation),\n debtRepayments: _n(cf.debtRepayment),\n },\n marketData: {\n price: _n(profile.price),\n marketCap: _n(profile.mktCap),\n sharesOutstanding: _n(inc.weightedAverageShsOut),\n ticker,\n },\n ratios: {\n peRatio: _n(rat.priceEarningsRatio),\n pbRatio: _n(rat.priceToBookRatio),\n psRatio: _n(rat.priceToSalesRatio),\n evToEbitda: _n(rat.enterpriseValueMultiple),\n roic: _n(rat.returnOnCapitalEmployed),\n roe: _n(rat.returnOnEquity),\n roa: _n(rat.returnOnAssets),\n currentRatio: _n(rat.currentRatio),\n debtToEquity: _n(rat.debtEquityRatio),\n grossMargin: _n(rat.grossProfitMargin),\n operatingMargin: _n(rat.operatingProfitMargin),\n netMargin: _n(rat.netProfitMargin),\n },\n })\n }\n\n return results\n}\n\n/** Fetch the current S&P 500 constituent list. */\nexport async function fetchFmpSp500(apiKey: string): Promise<string[]> {\n const data = (await _get(`${FMP_BASE}/sp500_constituent`, apiKey, {})) as any[]\n return data.map(d => d.symbol).filter(Boolean)\n}\n\nasync function _get(url: string, apiKey: string, params: Record<string, unknown>): Promise<unknown> {\n const query = new URLSearchParams({ ...Object.fromEntries(Object.entries(params).map(([k, v]) => [k, String(v)])), apikey: apiKey })\n const resp = await fetch(`${url}?${query}`)\n if (!resp.ok) throw new Error(`FMP request failed: ${resp.status} ${url}`)\n return resp.json()\n}\n\nfunction _n(v: unknown): number {\n if (v == null) return 0\n const n = Number(v)\n return isNaN(n) ? 0 : n\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/fetchers/yahoo/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Yahoo Finance fetcher — free, no API key required.\n * Uses Yahoo Finance's public JSON endpoints.\n *\n * For production use, consider using the `yahoo-finance2` npm package instead:\n * npm install yahoo-finance2\n *\n * Rate limit: ~2,000 requests/hour (unofficial). Add delays for bulk requests.\n */\n\nimport type {\n IncomeStatement,\n BalanceSheet,\n CashFlowStatement,\n MarketData,\n} from '../../types/index.js'\n\nconst BASE = 'https://query1.finance.yahoo.com/v10/finance/quoteSummary'\nconst HEADERS = {\n 'User-Agent': 'Mozilla/5.0 (compatible; fin-ratios/0.1)',\n 'Accept': 'application/json',\n}\n\nexport interface YahooFetchOptions {\n /** Additional modules to include (default covers all financial statements) */\n modules?: string[]\n}\n\nexport interface YahooData {\n marketData: MarketData\n income: IncomeStatement\n balance: BalanceSheet\n cashFlow: CashFlowStatement\n sector?: string\n industry?: string\n employeeCount?: number\n beta?: number\n dividendYield?: number\n}\n\n/**\n * Fetch comprehensive financial data for a stock ticker from Yahoo Finance.\n *\n * @example\n * const data = await fetchYahoo('AAPL')\n * const ratio = pe({ marketCap: data.marketData.marketCap, netIncome: data.income.netIncome })\n */\nexport async function fetchYahoo(\n ticker: string,\n options: YahooFetchOptions = {}\n): Promise<YahooData> {\n const modules = [\n 'financialData',\n 'defaultKeyStatistics',\n 'summaryDetail',\n 'assetProfile',\n 'incomeStatementHistory',\n 'balanceSheetHistory',\n 'cashflowStatementHistory',\n ...(options.modules ?? []),\n ].join(',')\n\n const url = `${BASE}/${encodeURIComponent(ticker)}?modules=${modules}`\n\n const resp = await fetch(url, { headers: HEADERS })\n if (!resp.ok) {\n throw new Error(`Yahoo Finance request failed: ${resp.status} for ${ticker}`)\n }\n\n const json = (await resp.json()) as Record<string, unknown>\n const result = (json?.quoteSummary as any)?.result?.[0]\n if (!result) {\n throw new Error(`No data returned for ${ticker}`)\n }\n\n const fd = result.financialData ?? {}\n const ks = result.defaultKeyStatistics ?? {}\n const sd = result.summaryDetail ?? {}\n const ap = result.assetProfile ?? {}\n\n // Income statement (TTM)\n const inc = result.incomeStatementHistory?.incomeStatementHistory?.[0] ?? {}\n // Balance sheet (most recent quarter/year)\n const bal = result.balanceSheetHistory?.balanceSheetHistory?.[0] ?? {}\n // Cash flow (most recent)\n const cf = result.cashflowStatementHistory?.cashflowStatementHistory?.[0] ?? {}\n\n const price = _n(fd.currentPrice) ?? _n(fd.regularMarketPrice) ?? 0\n const marketCap = _n(ks.marketCap) ?? 0\n const shares = _n(ks.sharesOutstanding) ?? 0\n\n const base: YahooData = {\n marketData: {\n price,\n marketCap,\n sharesOutstanding: shares,\n enterpriseValue: _n(ks.enterpriseValue),\n forwardEps: _n(ks.forwardEps),\n trailingEps: _n(ks.trailingEps),\n dividendPerShare: _n(sd.dividendRate),\n ticker,\n },\n income: {\n revenue: _n(inc.totalRevenue) ?? _n(fd.totalRevenue) ?? 0,\n grossProfit: _n(inc.grossProfit) ?? 0,\n cogs: (_n(inc.totalRevenue) ?? 0) - (_n(inc.grossProfit) ?? 0),\n ebit: _n(inc.ebit) ?? _n(fd.operatingCashflow) ?? 0,\n ebitda: _n(fd.ebitda) ?? 0,\n netIncome: _n(inc.netIncome) ?? _n(fd.netIncomeToCommon) ?? 0,\n interestExpense: Math.abs(_n(inc.interestExpense) ?? 0),\n incomeTaxExpense: _n(inc.incomeTaxExpense) ?? 0,\n ebt: _n(inc.pretaxIncome) ?? 0,\n depreciationAndAmortization: 0, // Not available in this module\n sharesOutstanding: shares,\n eps: _n(ks.trailingEps),\n },\n balance: {\n totalAssets: _n(bal.totalAssets) ?? 0,\n currentAssets: _n(bal.totalCurrentAssets) ?? 0,\n cash: _n(bal.cash) ?? _n(fd.totalCash) ?? 0,\n shortTermInvestments: _n(bal.shortTermInvestments),\n accountsReceivable: _n(bal.netReceivables) ?? 0,\n inventory: _n(bal.inventory) ?? 0,\n netPPE: _n(bal.propertyPlantEquipment) ?? 0,\n goodwill: _n(bal.goodWill),\n intangibleAssets: _n(bal.intangibleAssets),\n retainedEarnings: _n(bal.retainedEarnings) ?? 0,\n totalLiabilities: _n(bal.totalLiab) ?? 0,\n currentLiabilities: _n(bal.totalCurrentLiabilities) ?? 0,\n accountsPayable: _n(bal.accountsPayable) ?? 0,\n shortTermDebt: _n(bal.shortLongTermDebt),\n longTermDebt: _n(bal.longTermDebt) ?? _n(fd.totalDebt) ?? 0,\n totalDebt: _n(fd.totalDebt) ?? 0,\n totalEquity: _n(bal.totalStockholderEquity) ?? 0,\n sharesOutstanding: shares,\n },\n cashFlow: {\n operatingCashFlow: _n(cf.totalCashFromOperatingActivities) ?? _n(fd.operatingCashflow) ?? 0,\n capex: Math.abs(_n(cf.capitalExpenditures) ?? 0),\n investingCashFlow: _n(cf.totalCashflowsFromInvestingActivities),\n financingCashFlow: _n(cf.totalCashFromFinancingActivities),\n dividendsPaid: _n(cf.dividendsPaid),\n stockBasedCompensation: _n(cf.stockBasedCompensation),\n },\n sector: ap.sector,\n industry: ap.industry,\n }\n const empCount = _n(ap.fullTimeEmployees); if (empCount != null) base.employeeCount = empCount\n const betaVal = _n(ks.beta); if (betaVal != null) base.beta = betaVal\n const divYield = _n(sd.dividendYield); if (divYield != null) base.dividendYield = divYield\n return base\n}\n\n/**\n * Fetch price history (daily close prices) for risk calculations.\n *\n * @example\n * const prices = await fetchPriceHistory('AAPL', '1y')\n * const returns = pricesToReturns(prices)\n * const sharpe = sharpeRatio({ returns, riskFreeRate: 0.05 })\n */\nexport async function fetchPriceHistory(\n ticker: string,\n period: '1mo' | '3mo' | '6mo' | '1y' | '2y' | '5y' | 'max' = '1y'\n): Promise<{ dates: string[]; prices: number[] }> {\n const url = `https://query1.finance.yahoo.com/v8/finance/chart/${encodeURIComponent(ticker)}?range=${period}&interval=1d`\n const resp = await fetch(url, { headers: HEADERS })\n if (!resp.ok) throw new Error(`Price history request failed for ${ticker}`)\n\n const json = (await resp.json()) as any\n const chart = json?.chart?.result?.[0]\n if (!chart) throw new Error(`No price data for ${ticker}`)\n\n const timestamps: number[] = chart.timestamp ?? []\n const closes: number[] = chart.indicators?.quote?.[0]?.close ?? []\n\n const dates: string[] = []\n const prices: number[] = []\n\n for (let i = 0; i < timestamps.length; i++) {\n if (closes[i] != null) {\n dates.push(new Date((timestamps[i] ?? 0) * 1000).toISOString().split('T')[0]!)\n prices.push(closes[i] as number)\n }\n }\n\n return { dates, prices }\n}\n\nfunction _n(v: unknown): number | null {\n if (v == null) return null\n const raw = typeof v === 'object' ? (v as any).raw ?? v : v\n const n = Number(raw)\n return isNaN(n) ? null : n\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/fetchers/yahoo/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Yahoo Finance fetcher — free, no API key required.\n * Uses Yahoo Finance's public JSON endpoints.\n *\n * For production use, consider using the `yahoo-finance2` npm package instead:\n * npm install yahoo-finance2\n *\n * Rate limit: ~2,000 requests/hour (unofficial). Add delays for bulk requests.\n */\n\nimport type {\n IncomeStatement,\n BalanceSheet,\n CashFlowStatement,\n MarketData,\n} from '../../types/index.js'\n\nconst BASE = 'https://query1.finance.yahoo.com/v10/finance/quoteSummary'\nconst HEADERS = {\n 'User-Agent': 'Mozilla/5.0 (compatible; fin-ratios/0.1)',\n 'Accept': 'application/json',\n}\n\nexport interface YahooFetchOptions {\n /** Additional modules to include (default covers all financial statements) */\n modules?: string[]\n}\n\nexport interface YahooData {\n marketData: MarketData\n income: IncomeStatement\n balance: BalanceSheet\n cashFlow: CashFlowStatement\n sector?: string\n industry?: string\n employeeCount?: number\n beta?: number\n dividendYield?: number\n}\n\n/**\n * Fetch comprehensive financial data for a stock ticker from Yahoo Finance.\n *\n * @example\n * const data = await fetchYahoo('AAPL')\n * const ratio = pe({ marketCap: data.marketData.marketCap, netIncome: data.income.netIncome })\n */\nexport async function fetchYahoo(\n ticker: string,\n options: YahooFetchOptions = {}\n): Promise<YahooData> {\n const modules = [\n 'financialData',\n 'defaultKeyStatistics',\n 'summaryDetail',\n 'assetProfile',\n 'incomeStatementHistory',\n 'balanceSheetHistory',\n 'cashflowStatementHistory',\n ...(options.modules ?? []),\n ].join(',')\n\n const url = `${BASE}/${encodeURIComponent(ticker)}?modules=${modules}`\n\n const resp = await fetch(url, { headers: HEADERS })\n if (!resp.ok) {\n throw new Error(`Yahoo Finance request failed: ${resp.status} for ${ticker}`)\n }\n\n const json = (await resp.json()) as Record<string, unknown>\n const result = (json?.quoteSummary as any)?.result?.[0]\n if (!result) {\n throw new Error(`No data returned for ${ticker}`)\n }\n\n const fd = result.financialData ?? {}\n const ks = result.defaultKeyStatistics ?? {}\n const sd = result.summaryDetail ?? {}\n const ap = result.assetProfile ?? {}\n\n // Income statement (TTM)\n const inc = result.incomeStatementHistory?.incomeStatementHistory?.[0] ?? {}\n // Balance sheet (most recent quarter/year)\n const bal = result.balanceSheetHistory?.balanceSheetHistory?.[0] ?? {}\n // Cash flow (most recent)\n const cf = result.cashflowStatementHistory?.cashflowStatementHistory?.[0] ?? {}\n\n const price = _n(fd.currentPrice) ?? _n(fd.regularMarketPrice) ?? 0\n const marketCap = _n(ks.marketCap) ?? 0\n const shares = _n(ks.sharesOutstanding) ?? 0\n\n const base: YahooData = {\n marketData: {\n price,\n marketCap,\n sharesOutstanding: shares,\n enterpriseValue: _n(ks.enterpriseValue),\n forwardEps: _n(ks.forwardEps),\n trailingEps: _n(ks.trailingEps),\n dividendPerShare: _n(sd.dividendRate),\n ticker,\n },\n income: {\n revenue: _n(inc.totalRevenue) ?? _n(fd.totalRevenue) ?? 0,\n grossProfit: _n(inc.grossProfit) ?? 0,\n cogs: (_n(inc.totalRevenue) ?? 0) - (_n(inc.grossProfit) ?? 0),\n ebit: _n(inc.ebit) ?? _n(fd.operatingCashflow) ?? 0,\n ebitda: _n(fd.ebitda) ?? 0,\n netIncome: _n(inc.netIncome) ?? _n(fd.netIncomeToCommon) ?? 0,\n interestExpense: Math.abs(_n(inc.interestExpense) ?? 0),\n incomeTaxExpense: _n(inc.incomeTaxExpense) ?? 0,\n ebt: _n(inc.pretaxIncome) ?? 0,\n depreciationAndAmortization: 0, // Not available in this module\n sharesOutstanding: shares,\n eps: _n(ks.trailingEps),\n },\n balance: {\n totalAssets: _n(bal.totalAssets) ?? 0,\n currentAssets: _n(bal.totalCurrentAssets) ?? 0,\n cash: _n(bal.cash) ?? _n(fd.totalCash) ?? 0,\n shortTermInvestments: _n(bal.shortTermInvestments),\n accountsReceivable: _n(bal.netReceivables) ?? 0,\n inventory: _n(bal.inventory) ?? 0,\n netPPE: _n(bal.propertyPlantEquipment) ?? 0,\n goodwill: _n(bal.goodWill),\n intangibleAssets: _n(bal.intangibleAssets),\n retainedEarnings: _n(bal.retainedEarnings) ?? 0,\n totalLiabilities: _n(bal.totalLiab) ?? 0,\n currentLiabilities: _n(bal.totalCurrentLiabilities) ?? 0,\n accountsPayable: _n(bal.accountsPayable) ?? 0,\n shortTermDebt: _n(bal.shortLongTermDebt),\n longTermDebt: _n(bal.longTermDebt) ?? _n(fd.totalDebt) ?? 0,\n totalDebt: _n(fd.totalDebt) ?? 0,\n totalEquity: _n(bal.totalStockholderEquity) ?? 0,\n sharesOutstanding: shares,\n },\n cashFlow: {\n operatingCashFlow: _n(cf.totalCashFromOperatingActivities) ?? _n(fd.operatingCashflow) ?? 0,\n capex: Math.abs(_n(cf.capitalExpenditures) ?? 0),\n investingCashFlow: _n(cf.totalCashflowsFromInvestingActivities),\n financingCashFlow: _n(cf.totalCashFromFinancingActivities),\n dividendsPaid: _n(cf.dividendsPaid),\n stockBasedCompensation: _n(cf.stockBasedCompensation),\n },\n sector: ap.sector,\n industry: ap.industry,\n }\n const empCount = _n(ap.fullTimeEmployees); if (empCount != null) base.employeeCount = empCount\n const betaVal = _n(ks.beta); if (betaVal != null) base.beta = betaVal\n const divYield = _n(sd.dividendYield); if (divYield != null) base.dividendYield = divYield\n return base\n}\n\n/**\n * Fetch price history (daily close prices) for risk calculations.\n *\n * @example\n * const prices = await fetchPriceHistory('AAPL', '1y')\n * const returns = pricesToReturns(prices)\n * const sharpe = sharpeRatio({ returns, riskFreeRate: 0.05 })\n */\nexport async function fetchPriceHistory(\n ticker: string,\n period: '1mo' | '3mo' | '6mo' | '1y' | '2y' | '5y' | 'max' = '1y'\n): Promise<{ dates: string[]; prices: number[] }> {\n const url = `https://query1.finance.yahoo.com/v8/finance/chart/${encodeURIComponent(ticker)}?range=${period}&interval=1d`\n const resp = await fetch(url, { headers: HEADERS })\n if (!resp.ok) throw new Error(`Price history request failed for ${ticker}`)\n\n const json = (await resp.json()) as any\n const chart = json?.chart?.result?.[0]\n if (!chart) throw new Error(`No price data for ${ticker}`)\n\n const timestamps: number[] = chart.timestamp ?? []\n const closes: number[] = chart.indicators?.quote?.[0]?.close ?? []\n\n const dates: string[] = []\n const prices: number[] = []\n\n for (let i = 0; i < timestamps.length; i++) {\n if (closes[i] != null) {\n dates.push(new Date((timestamps[i] ?? 0) * 1000).toISOString().split('T')[0]!)\n prices.push(closes[i] as number)\n }\n }\n\n return { dates, prices }\n}\n\nfunction _n(v: unknown): number | null {\n if (v == null) return null\n const raw = typeof v === 'object' ? (v as any).raw ?? v : v\n const n = Number(raw)\n return isNaN(n) ? null : n\n}\n"]}
|
package/dist/hooks/index.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/safe-divide.ts","../../src/ratios/valuation/index.ts","../../src/ratios/profitability/index.ts","../../src/ratios/liquidity/index.ts","../../src/ratios/solvency/index.ts","../../src/ratios/efficiency/index.ts","../../src/ratios/cashflow/index.ts","../../src/ratios/composite/index.ts","../../src/utils/compute-all.ts","../../src/utils/scenario-dcf.ts","../../src/hooks/index.ts"],"names":["useState","useRef","useCallback","useEffect"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Divides numerator by denominator.\n * Returns null instead of Infinity/NaN when denominator is 0 or either input is null/undefined.\n */\nexport function safeDivide(\n numerator: number | null | undefined,\n denominator: number | null | undefined\n): number | null {\n if (numerator == null || denominator == null) return null\n if (denominator === 0) return null\n return numerator / denominator\n}\n","import { safeDivide } from '../../utils/safe-divide.js'\n\n// ── P/E ──────────────────────────────────────────────────────────────────────\n\nexport function pe(input: {\n marketCap: number\n netIncome: number\n}): number | null {\n return safeDivide(input.marketCap, input.netIncome)\n}\npe.formula = 'Market Capitalization / Net Income'\npe.description = 'Trailing price-to-earnings ratio. How much investors pay per dollar of earnings.'\n\nexport function forwardPe(input: {\n price: number\n forwardEps: number\n}): number | null {\n return safeDivide(input.price, input.forwardEps)\n}\nforwardPe.formula = 'Stock Price / Forward EPS Estimate'\nforwardPe.description = 'P/E based on next twelve months analyst EPS estimate.'\n\n// ── PEG ──────────────────────────────────────────────────────────────────────\n\nexport function peg(input: {\n peRatio: number\n epsGrowthRatePercent: number\n}): number | null {\n return safeDivide(input.peRatio, input.epsGrowthRatePercent)\n}\npeg.formula = 'P/E Ratio / EPS Annual Growth Rate (%)'\npeg.description = 'PEG ratio. < 1 may indicate undervaluation relative to growth.'\n\n// ── P/B ──────────────────────────────────────────────────────────────────────\n\nexport function pb(input: {\n marketCap: number\n totalEquity: number\n}): number | null {\n return safeDivide(input.marketCap, input.totalEquity)\n}\npb.formula = 'Market Capitalization / Total Shareholders Equity'\npb.description = 'Price-to-book ratio. < 1 may indicate trading below net asset value.'\n\n// ── P/S ──────────────────────────────────────────────────────────────────────\n\nexport function ps(input: {\n marketCap: number\n revenue: number\n}): number | null {\n return safeDivide(input.marketCap, input.revenue)\n}\nps.formula = 'Market Capitalization / Revenue'\nps.description = 'Price-to-sales ratio. Useful when earnings are negative.'\n\n// ── P/FCF ─────────────────────────────────────────────────────────────────────\n\nexport function pFcf(input: {\n marketCap: number\n operatingCashFlow: number\n capex: number\n}): number | null {\n const fcf = input.operatingCashFlow - Math.abs(input.capex)\n return safeDivide(input.marketCap, fcf)\n}\npFcf.formula = 'Market Capitalization / (Operating Cash Flow - Capex)'\npFcf.description = 'Price-to-free-cash-flow. Often considered cleaner than P/E.'\n\n// ── Enterprise Value ──────────────────────────────────────────────────────────\n\nexport function enterpriseValue(input: {\n marketCap: number\n totalDebt: number\n cash: number\n minorityInterest?: number | null\n preferredStock?: number | null\n}): number {\n return (\n input.marketCap +\n input.totalDebt -\n input.cash +\n (input.minorityInterest ?? 0) +\n (input.preferredStock ?? 0)\n )\n}\nenterpriseValue.formula = 'Market Cap + Total Debt - Cash + Minority Interest + Preferred Stock'\nenterpriseValue.description = 'Enterprise value — the theoretical takeover price of a company.'\n\n// ── EV Multiples ─────────────────────────────────────────────────────────────\n\nexport function evEbitda(input: {\n enterpriseValue: number\n ebitda: number\n}): number | null {\n return safeDivide(input.enterpriseValue, input.ebitda)\n}\nevEbitda.formula = 'Enterprise Value / EBITDA'\nevEbitda.description = 'Capital-structure-neutral valuation multiple. Popular in LBO analysis.'\n\nexport function evEbit(input: {\n enterpriseValue: number\n ebit: number\n}): number | null {\n return safeDivide(input.enterpriseValue, input.ebit)\n}\nevEbit.formula = 'Enterprise Value / EBIT'\nevEbit.description = 'Like EV/EBITDA but accounts for depreciation-heavy businesses.'\n\nexport function evRevenue(input: {\n enterpriseValue: number\n revenue: number\n}): number | null {\n return safeDivide(input.enterpriseValue, input.revenue)\n}\nevRevenue.formula = 'Enterprise Value / Revenue'\nevRevenue.description = 'Useful for high-growth companies without positive EBITDA.'\n\nexport function evFcf(input: {\n enterpriseValue: number\n freeCashFlow: number\n}): number | null {\n return safeDivide(input.enterpriseValue, input.freeCashFlow)\n}\nevFcf.formula = 'Enterprise Value / Free Cash Flow'\nevFcf.description = 'EV-to-free-cash-flow. Preferred by value investors.'\n\nexport function evInvestedCapital(input: {\n enterpriseValue: number\n investedCapital: number\n}): number | null {\n return safeDivide(input.enterpriseValue, input.investedCapital)\n}\nevInvestedCapital.formula = 'Enterprise Value / Invested Capital'\nevInvestedCapital.description = 'Indicates whether the market values the company above its invested capital base.'\n\n// ── Tobin's Q ─────────────────────────────────────────────────────────────────\n\nexport function tobinsQ(input: {\n marketCap: number\n totalDebt: number\n totalAssets: number\n}): number | null {\n const marketValue = input.marketCap + input.totalDebt\n return safeDivide(marketValue, input.totalAssets)\n}\ntobinsQ.formula = '(Market Cap + Total Debt) / Total Assets'\ntobinsQ.description = 'Q > 1 = market values firm above replacement cost. Q < 1 = below.'\n\n// ── Graham Number ─────────────────────────────────────────────────────────────\n\nexport function grahamNumber(input: {\n eps: number\n bookValuePerShare: number\n}): number | null {\n if (input.eps <= 0 || input.bookValuePerShare <= 0) return null\n return Math.sqrt(22.5 * input.eps * input.bookValuePerShare)\n}\ngrahamNumber.formula = 'sqrt(22.5 × EPS × Book Value Per Share)'\ngrahamNumber.description = 'Ben Graham\\'s estimate of fair value. Buy below, sell above.'\n\n// ── Ben Graham Intrinsic Value ─────────────────────────────────────────────────\n\nexport function grahamIntrinsicValue(input: {\n eps: number\n growthRate: number\n aaaBondYield: number\n}): number | null {\n if (input.aaaBondYield <= 0) return null\n // Graham's revised formula: V* = EPS × (8.5 + 2g) × 4.4 / Y\n return safeDivide(\n input.eps * (8.5 + 2 * input.growthRate) * 4.4,\n input.aaaBondYield\n )\n}\ngrahamIntrinsicValue.formula = 'EPS × (8.5 + 2 × Growth Rate) × 4.4 / AAA Bond Yield'\ngrahamIntrinsicValue.description = 'Graham\\'s 1962 revised intrinsic value formula. Use growth rate as %, e.g. 15.'\n","import { safeDivide } from '../../utils/safe-divide.js'\n\n// ── Margin Ratios ─────────────────────────────────────────────────────────────\n\nexport function grossMargin(input: {\n grossProfit: number\n revenue: number\n}): number | null {\n return safeDivide(input.grossProfit, input.revenue)\n}\ngrossMargin.formula = 'Gross Profit / Revenue'\ngrossMargin.description = 'Percentage of revenue remaining after cost of goods sold.'\n\nexport function operatingMargin(input: {\n ebit: number\n revenue: number\n}): number | null {\n return safeDivide(input.ebit, input.revenue)\n}\noperatingMargin.formula = 'EBIT / Revenue'\noperatingMargin.description = 'Operating income as a percentage of revenue.'\n\nexport function ebitdaMargin(input: {\n ebitda: number\n revenue: number\n}): number | null {\n return safeDivide(input.ebitda, input.revenue)\n}\nebitdaMargin.formula = 'EBITDA / Revenue'\nebitdaMargin.description = 'Earnings before interest, taxes, D&A as % of revenue.'\n\nexport function netProfitMargin(input: {\n netIncome: number\n revenue: number\n}): number | null {\n return safeDivide(input.netIncome, input.revenue)\n}\nnetProfitMargin.formula = 'Net Income / Revenue'\nnetProfitMargin.description = 'Bottom-line profitability after all expenses.'\n\nexport function nopatMargin(input: {\n nopat: number\n revenue: number\n}): number | null {\n return safeDivide(input.nopat, input.revenue)\n}\nnopatMargin.formula = 'NOPAT / Revenue'\nnopatMargin.description = 'Net operating profit after tax as % of revenue.'\n\n// ── Return Ratios ─────────────────────────────────────────────────────────────\n\nexport function roe(input: {\n netIncome: number\n avgTotalEquity: number\n}): number | null {\n return safeDivide(input.netIncome, input.avgTotalEquity)\n}\nroe.formula = 'Net Income / Average Total Equity'\nroe.description = 'Return on equity — how efficiently a company uses shareholder capital.'\n\nexport function roa(input: {\n netIncome: number\n avgTotalAssets: number\n}): number | null {\n return safeDivide(input.netIncome, input.avgTotalAssets)\n}\nroa.formula = 'Net Income / Average Total Assets'\nroa.description = 'Return on assets — how efficiently assets are used to generate profit.'\n\nexport function nopat(input: {\n ebit: number\n taxRate: number\n}): number {\n return input.ebit * (1 - input.taxRate)\n}\nnopat.formula = 'EBIT × (1 - Effective Tax Rate)'\nnopat.description = 'Net operating profit after tax — removes financing effects.'\n\nexport function roic(input: {\n nopat: number\n investedCapital: number\n}): number | null {\n return safeDivide(input.nopat, input.investedCapital)\n}\nroic.formula = 'NOPAT / Invested Capital'\nroic.description = 'ROIC vs WACC determines whether a company creates or destroys value.'\n\nexport function roce(input: {\n ebit: number\n totalAssets: number\n currentLiabilities: number\n}): number | null {\n const capitalEmployed = input.totalAssets - input.currentLiabilities\n return safeDivide(input.ebit, capitalEmployed)\n}\nroce.formula = 'EBIT / (Total Assets - Current Liabilities)'\nroce.description = 'Return on capital employed. Includes both equity and long-term debt.'\n\nexport function rote(input: {\n netIncome: number\n avgTotalEquity: number\n avgGoodwill: number\n avgIntangibleAssets: number\n}): number | null {\n const tangibleEquity = input.avgTotalEquity - input.avgGoodwill - input.avgIntangibleAssets\n return safeDivide(input.netIncome, tangibleEquity)\n}\nrote.formula = 'Net Income / (Avg Equity - Avg Goodwill - Avg Intangibles)'\nrote.description = 'Return on tangible equity. Strips acquisition premiums from the denominator.'\n\n// ── DuPont Analysis ───────────────────────────────────────────────────────────\n\nexport interface DuPont3Factor {\n netProfitMargin: number | null\n assetTurnover: number | null\n equityMultiplier: number | null\n roe: number | null\n}\n\nexport function duPont3(input: {\n netIncome: number\n revenue: number\n avgTotalAssets: number\n avgTotalEquity: number\n}): DuPont3Factor {\n const margin = safeDivide(input.netIncome, input.revenue)\n const turnover = safeDivide(input.revenue, input.avgTotalAssets)\n const multiplier = safeDivide(input.avgTotalAssets, input.avgTotalEquity)\n const roeVal =\n margin != null && turnover != null && multiplier != null\n ? margin * turnover * multiplier\n : null\n return { netProfitMargin: margin, assetTurnover: turnover, equityMultiplier: multiplier, roe: roeVal }\n}\nduPont3.formula = 'ROE = Net Profit Margin × Asset Turnover × Equity Multiplier'\nduPont3.description = '3-factor DuPont decomposition of ROE.'\n\n// ── Per-Employee ──────────────────────────────────────────────────────────────\n\nexport function revenuePerEmployee(input: {\n revenue: number\n employeeCount: number\n}): number | null {\n return safeDivide(input.revenue, input.employeeCount)\n}\nrevenuePerEmployee.formula = 'Revenue / Full-Time Employees'\nrevenuePerEmployee.description = 'Measures workforce productivity.'\n\nexport function profitPerEmployee(input: {\n netIncome: number\n employeeCount: number\n}): number | null {\n return safeDivide(input.netIncome, input.employeeCount)\n}\nprofitPerEmployee.formula = 'Net Income / Full-Time Employees'\nprofitPerEmployee.description = 'Net income generated per employee.'\n\n// ── Invested Capital ──────────────────────────────────────────────────────────\n\nexport function investedCapital(input: {\n totalEquity: number\n totalDebt: number\n cash: number\n}): number {\n return input.totalEquity + input.totalDebt - input.cash\n}\ninvestedCapital.formula = 'Total Equity + Total Debt - Excess Cash'\ninvestedCapital.description = 'Capital deployed to generate operating returns.'\n","import { safeDivide } from '../../utils/safe-divide.js'\n\nexport function currentRatio(input: {\n currentAssets: number\n currentLiabilities: number\n}): number | null {\n return safeDivide(input.currentAssets, input.currentLiabilities)\n}\ncurrentRatio.formula = 'Current Assets / Current Liabilities'\ncurrentRatio.description = 'Ability to pay short-term obligations. > 1 generally healthy.'\n\nexport function quickRatio(input: {\n cash: number\n shortTermInvestments: number\n accountsReceivable: number\n currentLiabilities: number\n}): number | null {\n const liquid = input.cash + input.shortTermInvestments + input.accountsReceivable\n return safeDivide(liquid, input.currentLiabilities)\n}\nquickRatio.formula = '(Cash + ST Investments + Accounts Receivable) / Current Liabilities'\nquickRatio.description = 'Liquidity excluding inventory. More conservative than current ratio.'\n\nexport function cashRatio(input: {\n cash: number\n shortTermInvestments: number\n currentLiabilities: number\n}): number | null {\n return safeDivide(input.cash + input.shortTermInvestments, input.currentLiabilities)\n}\ncashRatio.formula = '(Cash + Short-Term Investments) / Current Liabilities'\ncashRatio.description = 'Most conservative liquidity measure. Only counts actual cash.'\n\nexport function operatingCashFlowRatio(input: {\n operatingCashFlow: number\n currentLiabilities: number\n}): number | null {\n return safeDivide(input.operatingCashFlow, input.currentLiabilities)\n}\noperatingCashFlowRatio.formula = 'Operating Cash Flow / Current Liabilities'\noperatingCashFlowRatio.description = 'How well operating cash flow covers short-term obligations.'\n\n// ── Working Capital Cycle ─────────────────────────────────────────────────────\n\nexport function dso(input: {\n accountsReceivable: number\n revenue: number\n}): number | null {\n return safeDivide(input.accountsReceivable * 365, input.revenue)\n}\ndso.formula = '(Accounts Receivable / Revenue) × 365'\ndso.description = 'Days Sales Outstanding — average days to collect payment after a sale.'\n\nexport function dio(input: {\n inventory: number\n cogs: number\n}): number | null {\n return safeDivide(input.inventory * 365, input.cogs)\n}\ndio.formula = '(Inventory / COGS) × 365'\ndio.description = 'Days Inventory Outstanding — average days inventory is held before sale.'\n\nexport function dpo(input: {\n accountsPayable: number\n cogs: number\n}): number | null {\n return safeDivide(input.accountsPayable * 365, input.cogs)\n}\ndpo.formula = '(Accounts Payable / COGS) × 365'\ndpo.description = 'Days Payable Outstanding — average days taken to pay suppliers.'\n\nexport function cashConversionCycle(input: {\n dso: number\n dio: number\n dpo: number\n}): number {\n return input.dso + input.dio - input.dpo\n}\ncashConversionCycle.formula = 'DSO + DIO - DPO'\ncashConversionCycle.description = 'Days from cash outflow (inventory) to cash inflow (collections). Lower is better.'\n\nexport function defensiveIntervalRatio(input: {\n cash: number\n shortTermInvestments: number\n accountsReceivable: number\n dailyOperatingExpenses: number\n}): number | null {\n const liquid = input.cash + input.shortTermInvestments + input.accountsReceivable\n return safeDivide(liquid, input.dailyOperatingExpenses)\n}\ndefensiveIntervalRatio.formula = '(Cash + ST Investments + AR) / Daily Operating Expenses'\ndefensiveIntervalRatio.description = 'Days the company can operate using liquid assets alone, without new revenue.'\n","import { safeDivide } from '../../utils/safe-divide.js'\n\nexport function debtToEquity(input: {\n totalDebt: number\n totalEquity: number\n}): number | null {\n return safeDivide(input.totalDebt, input.totalEquity)\n}\ndebtToEquity.formula = 'Total Debt / Total Equity'\ndebtToEquity.description = 'Financial leverage. Higher = more debt-financed.'\n\nexport function netDebtToEquity(input: {\n totalDebt: number\n cash: number\n totalEquity: number\n}): number | null {\n const netDebt = input.totalDebt - input.cash\n return safeDivide(netDebt, input.totalEquity)\n}\nnetDebtToEquity.formula = '(Total Debt - Cash) / Total Equity'\nnetDebtToEquity.description = 'Net leverage ratio. Negative = net cash position.'\n\nexport function netDebtToEbitda(input: {\n totalDebt: number\n cash: number\n ebitda: number\n}): number | null {\n const netDebt = input.totalDebt - input.cash\n return safeDivide(netDebt, input.ebitda)\n}\nnetDebtToEbitda.formula = '(Total Debt - Cash) / EBITDA'\nnetDebtToEbitda.description = 'Years to repay net debt from EBITDA. Lenders often require < 3x.'\n\nexport function debtToAssets(input: {\n totalDebt: number\n totalAssets: number\n}): number | null {\n return safeDivide(input.totalDebt, input.totalAssets)\n}\ndebtToAssets.formula = 'Total Debt / Total Assets'\ndebtToAssets.description = 'Proportion of assets financed by debt.'\n\nexport function debtToCapital(input: {\n totalDebt: number\n totalEquity: number\n}): number | null {\n return safeDivide(input.totalDebt, input.totalDebt + input.totalEquity)\n}\ndebtToCapital.formula = 'Total Debt / (Total Debt + Total Equity)'\ndebtToCapital.description = 'Proportion of capital structure that is debt.'\n\nexport function interestCoverageRatio(input: {\n ebit: number\n interestExpense: number\n}): number | null {\n return safeDivide(input.ebit, input.interestExpense)\n}\ninterestCoverageRatio.formula = 'EBIT / Interest Expense'\ninterestCoverageRatio.description = 'Times interest is covered by operating earnings. < 1.5 is risky.'\n\nexport function ebitdaCoverageRatio(input: {\n ebitda: number\n interestExpense: number\n}): number | null {\n return safeDivide(input.ebitda, input.interestExpense)\n}\nebitdaCoverageRatio.formula = 'EBITDA / Interest Expense'\nebitdaCoverageRatio.description = 'Softer coverage ratio including D&A add-back.'\n\nexport function debtServiceCoverageRatio(input: {\n netOperatingIncome: number\n annualDebtService: number\n}): number | null {\n return safeDivide(input.netOperatingIncome, input.annualDebtService)\n}\ndebtServiceCoverageRatio.formula = 'Net Operating Income / Annual Debt Service (Principal + Interest)'\ndebtServiceCoverageRatio.description = 'Lenders require DSCR > 1.25. Critical for real estate and leveraged deals.'\n\nexport function fixedChargeCoverageRatio(input: {\n ebit: number\n fixedCharges: number\n interestExpense: number\n}): number | null {\n return safeDivide(input.ebit + input.fixedCharges, input.fixedCharges + input.interestExpense)\n}\nfixedChargeCoverageRatio.formula = '(EBIT + Fixed Charges) / (Fixed Charges + Interest Expense)'\nfixedChargeCoverageRatio.description = 'Covers lease payments and other fixed obligations beyond interest.'\n\nexport function equityMultiplier(input: {\n totalAssets: number\n totalEquity: number\n}): number | null {\n return safeDivide(input.totalAssets, input.totalEquity)\n}\nequityMultiplier.formula = 'Total Assets / Total Equity'\nequityMultiplier.description = 'Leverage component of DuPont analysis.'\n","import { safeDivide } from '../../utils/safe-divide.js'\n\nexport function assetTurnover(input: {\n revenue: number\n avgTotalAssets: number\n}): number | null {\n return safeDivide(input.revenue, input.avgTotalAssets)\n}\nassetTurnover.formula = 'Revenue / Average Total Assets'\nassetTurnover.description = 'Sales generated per dollar of total assets.'\n\nexport function fixedAssetTurnover(input: {\n revenue: number\n avgNetPPE: number\n}): number | null {\n return safeDivide(input.revenue, input.avgNetPPE)\n}\nfixedAssetTurnover.formula = 'Revenue / Average Net PP&E'\nfixedAssetTurnover.description = 'Efficiency of physical asset use. Low in capital-intensive industries.'\n\nexport function inventoryTurnover(input: {\n cogs: number\n avgInventory: number\n}): number | null {\n return safeDivide(input.cogs, input.avgInventory)\n}\ninventoryTurnover.formula = 'COGS / Average Inventory'\ninventoryTurnover.description = 'How many times inventory is sold per year. Higher = less cash tied up.'\n\nexport function receivablesTurnover(input: {\n revenue: number\n avgAccountsReceivable: number\n}): number | null {\n return safeDivide(input.revenue, input.avgAccountsReceivable)\n}\nreceivablesTurnover.formula = 'Revenue / Average Accounts Receivable'\nreceivablesTurnover.description = 'How quickly the company collects what it is owed.'\n\nexport function payablesTurnover(input: {\n cogs: number\n avgAccountsPayable: number\n}): number | null {\n return safeDivide(input.cogs, input.avgAccountsPayable)\n}\npayablesTurnover.formula = 'COGS / Average Accounts Payable'\npayablesTurnover.description = 'How quickly the company pays its suppliers.'\n\nexport function workingCapitalTurnover(input: {\n revenue: number\n avgWorkingCapital: number\n}): number | null {\n return safeDivide(input.revenue, input.avgWorkingCapital)\n}\nworkingCapitalTurnover.formula = 'Revenue / Average Working Capital'\nworkingCapitalTurnover.description = 'Revenue generated from each dollar of working capital.'\n\nexport function capitalTurnover(input: {\n revenue: number\n investedCapital: number\n}): number | null {\n return safeDivide(input.revenue, input.investedCapital)\n}\ncapitalTurnover.formula = 'Revenue / Invested Capital'\ncapitalTurnover.description = 'Sales generated per dollar of invested capital.'\n\nexport function operatingLeverage(input: {\n ebitCurrent: number\n ebitPrior: number\n revenueCurrent: number\n revenuePrior: number\n}): number | null {\n const ebitChange = safeDivide(\n input.ebitCurrent - input.ebitPrior,\n Math.abs(input.ebitPrior)\n )\n const revenueChange = safeDivide(\n input.revenueCurrent - input.revenuePrior,\n Math.abs(input.revenuePrior)\n )\n return safeDivide(ebitChange, revenueChange)\n}\noperatingLeverage.formula = '% Change in EBIT / % Change in Revenue'\noperatingLeverage.description = 'Sensitivity of operating income to revenue changes. High = more fixed costs.'\n","import { safeDivide } from '../../utils/safe-divide.js'\n\nexport function freeCashFlow(input: {\n operatingCashFlow: number\n capex: number\n}): number {\n return input.operatingCashFlow - Math.abs(input.capex)\n}\nfreeCashFlow.formula = 'Operating Cash Flow - Capital Expenditures'\nfreeCashFlow.description = 'Cash available after maintaining/growing asset base. The most important cash flow metric.'\n\nexport function leveredFcf(input: {\n freeCashFlow: number\n debtIssuance: number\n debtRepayments: number\n}): number {\n return input.freeCashFlow + input.debtIssuance - input.debtRepayments\n}\nleveredFcf.formula = 'FCF + Net Debt Change (Issuance - Repayments)'\nleveredFcf.description = 'FCF after accounting for debt financing activities.'\n\nexport function unleveredFcf(input: {\n nopat: number\n depreciationAndAmortization: number\n capex: number\n changeInWorkingCapital: number\n}): number {\n return input.nopat + input.depreciationAndAmortization - Math.abs(input.capex) - input.changeInWorkingCapital\n}\nunleveredFcf.formula = 'NOPAT + D&A - Capex - Change in Working Capital'\nunleveredFcf.description = 'FCF before debt payments — used in DCF valuation as FCFF.'\n\nexport function ownerEarnings(input: {\n netIncome: number\n depreciationAndAmortization: number\n maintenanceCapex: number\n changeInWorkingCapital?: number\n}): number {\n return (\n input.netIncome +\n input.depreciationAndAmortization -\n input.maintenanceCapex -\n (input.changeInWorkingCapital ?? 0)\n )\n}\nownerEarnings.formula = 'Net Income + D&A - Maintenance Capex - Change in WC'\nownerEarnings.description = 'Buffett\\'s owner earnings — true economic earnings available to shareholders.'\n\nexport function fcfYield(input: {\n freeCashFlow: number\n marketCap: number\n}): number | null {\n return safeDivide(input.freeCashFlow, input.marketCap)\n}\nfcfYield.formula = 'Free Cash Flow / Market Capitalization'\nfcfYield.description = 'FCF per dollar invested. Inverse of P/FCF. Higher = cheaper.'\n\nexport function fcfMargin(input: {\n freeCashFlow: number\n revenue: number\n}): number | null {\n return safeDivide(input.freeCashFlow, input.revenue)\n}\nfcfMargin.formula = 'Free Cash Flow / Revenue'\nfcfMargin.description = 'FCF generated per dollar of revenue.'\n\nexport function fcfConversion(input: {\n freeCashFlow: number\n netIncome: number\n}): number | null {\n return safeDivide(input.freeCashFlow, input.netIncome)\n}\nfcfConversion.formula = 'Free Cash Flow / Net Income'\nfcfConversion.description = 'FCF conversion > 1 means earnings are backed by real cash. < 1 raises quality concerns.'\n\nexport function ocfToSales(input: {\n operatingCashFlow: number\n revenue: number\n}): number | null {\n return safeDivide(input.operatingCashFlow, input.revenue)\n}\nocfToSales.formula = 'Operating Cash Flow / Revenue'\nocfToSales.description = 'Cash generated from operations per dollar of sales.'\n\nexport function capexToRevenue(input: {\n capex: number\n revenue: number\n}): number | null {\n return safeDivide(Math.abs(input.capex), input.revenue)\n}\ncapexToRevenue.formula = 'Capital Expenditures / Revenue'\ncapexToRevenue.description = 'Investment intensity. High in capital-intensive industries like manufacturing.'\n\nexport function capexToDepreciation(input: {\n capex: number\n depreciation: number\n}): number | null {\n return safeDivide(Math.abs(input.capex), input.depreciation)\n}\ncapexToDepreciation.formula = 'Capital Expenditures / Depreciation'\ncapexToDepreciation.description = '> 1 = company is investing more than assets are aging (growth). < 1 = under-investing.'\n\nexport function cashReturnOnAssets(input: {\n operatingCashFlow: number\n totalAssets: number\n}): number | null {\n return safeDivide(input.operatingCashFlow, input.totalAssets)\n}\ncashReturnOnAssets.formula = 'Operating Cash Flow / Total Assets'\ncashReturnOnAssets.description = 'Cash-based ROA. Harder to manipulate than accrual-based ROA.'\n","import { safeDivide } from '../../utils/safe-divide.js'\n\n// ── Piotroski F-Score ─────────────────────────────────────────────────────────\n\nexport interface PiotroskiInput {\n current: {\n netIncome: number\n totalAssets: number\n operatingCashFlow: number\n longTermDebt: number\n currentAssets: number\n currentLiabilities: number\n sharesOutstanding: number\n grossProfit: number\n revenue: number\n }\n prior: {\n netIncome: number\n totalAssets: number\n longTermDebt: number\n currentAssets: number\n currentLiabilities: number\n sharesOutstanding: number\n grossProfit: number\n revenue: number\n }\n}\n\nexport interface PiotroskiResult {\n score: number\n signals: {\n // Profitability\n roa_positive: boolean\n ocf_positive: boolean\n roa_improving: boolean\n quality_earnings: boolean\n // Leverage / Liquidity\n lower_leverage: boolean\n higher_liquidity: boolean\n no_dilution: boolean\n // Operating Efficiency\n higher_gross_margin: boolean\n higher_asset_turnover: boolean\n }\n interpretation: string\n}\n\nexport function piotroskiFScore(input: PiotroskiInput): PiotroskiResult {\n const { current, prior } = input\n\n const roaCurrent = (current.netIncome / current.totalAssets)\n const roaPrior = (prior.netIncome / prior.totalAssets)\n const leverageCurrent = current.totalAssets > 0 ? current.longTermDebt / current.totalAssets : 0\n const leveragePrior = prior.totalAssets > 0 ? prior.longTermDebt / prior.totalAssets : 0\n const crCurrent = current.currentLiabilities > 0 ? current.currentAssets / current.currentLiabilities : 0\n const crPrior = prior.currentLiabilities > 0 ? prior.currentAssets / prior.currentLiabilities : 0\n const gmCurrent = current.revenue > 0 ? current.grossProfit / current.revenue : 0\n const gmPrior = prior.revenue > 0 ? prior.grossProfit / prior.revenue : 0\n const atCurrent = current.totalAssets > 0 ? current.revenue / current.totalAssets : 0\n const atPrior = prior.totalAssets > 0 ? prior.revenue / prior.totalAssets : 0\n\n const signals = {\n // F1: ROA positive\n roa_positive: roaCurrent > 0,\n // F2: Operating cash flow positive\n ocf_positive: current.operatingCashFlow > 0,\n // F3: ROA improving year over year\n roa_improving: roaCurrent > roaPrior,\n // F4: Accruals — OCF > NI (quality earnings, cash-backed)\n quality_earnings: current.operatingCashFlow > current.netIncome,\n // F5: Long-term debt / assets ratio declined\n lower_leverage: leverageCurrent < leveragePrior,\n // F6: Current ratio improved\n higher_liquidity: crCurrent > crPrior,\n // F7: No new shares issued (dilution)\n no_dilution: current.sharesOutstanding <= prior.sharesOutstanding,\n // F8: Gross margin improved\n higher_gross_margin: gmCurrent > gmPrior,\n // F9: Asset turnover improved\n higher_asset_turnover: atCurrent > atPrior,\n }\n\n const score = Object.values(signals).filter(Boolean).length\n\n let interpretation = ''\n if (score >= 8) interpretation = 'Strong (8-9): High financial strength, potential value opportunity'\n else if (score >= 6) interpretation = 'Good (6-7): Reasonably healthy fundamentals'\n else if (score >= 4) interpretation = 'Neutral (4-5): Mixed signals, further analysis needed'\n else interpretation = 'Weak (0-3): Multiple red flags, high risk'\n\n return { score, signals, interpretation }\n}\npiotroskiFScore.formula = '9 binary signals across Profitability, Leverage/Liquidity, Operating Efficiency'\npiotroskiFScore.description = 'F-Score 0-9. >= 8 is strong buy signal. <= 2 is short signal.'\n\n// ── Altman Z-Score ────────────────────────────────────────────────────────────\n\nexport interface AltmanInput {\n workingCapital: number\n retainedEarnings: number\n ebit: number\n marketCap: number\n totalLiabilities: number\n totalAssets: number\n revenue: number\n}\n\nexport interface AltmanResult {\n z: number\n x1: number\n x2: number\n x3: number\n x4: number\n x5: number\n zone: 'safe' | 'grey' | 'distress'\n interpretation: string\n}\n\nexport function altmanZScore(input: AltmanInput): AltmanResult | null {\n if (input.totalAssets === 0 || input.totalLiabilities === 0) return null\n\n const x1 = input.workingCapital / input.totalAssets\n const x2 = input.retainedEarnings / input.totalAssets\n const x3 = input.ebit / input.totalAssets\n const x4 = input.marketCap / input.totalLiabilities\n const x5 = input.revenue / input.totalAssets\n\n const z = 1.2 * x1 + 1.4 * x2 + 3.3 * x3 + 0.6 * x4 + 1.0 * x5\n\n let zone: 'safe' | 'grey' | 'distress'\n let interpretation: string\n if (z > 2.99) {\n zone = 'safe'\n interpretation = 'Safe zone (Z > 2.99): Low probability of bankruptcy'\n } else if (z > 1.81) {\n zone = 'grey'\n interpretation = 'Grey zone (1.81 < Z < 2.99): Uncertain, monitor closely'\n } else {\n zone = 'distress'\n interpretation = 'Distress zone (Z < 1.81): High probability of financial distress'\n }\n\n return { z, x1, x2, x3, x4, x5, zone, interpretation }\n}\naltmanZScore.formula = '1.2×X1 + 1.4×X2 + 3.3×X3 + 0.6×X4 + 1.0×X5 (public manufacturing)'\naltmanZScore.description = 'Bankruptcy prediction model. Safe > 2.99, Distress < 1.81.'\n\n// ── Beneish M-Score ───────────────────────────────────────────────────────────\n\nexport interface BeneishInput {\n current: {\n revenue: number\n accountsReceivable: number\n grossProfit: number\n totalAssets: number\n depreciation: number\n ppGross: number\n sgaExpense: number\n totalDebt: number\n netIncome: number\n cashFlowFromOps: number\n }\n prior: {\n revenue: number\n accountsReceivable: number\n grossProfit: number\n totalAssets: number\n depreciation: number\n ppGross: number\n sgaExpense: number\n totalDebt: number\n }\n}\n\nexport interface BeneishResult {\n mScore: number\n variables: {\n dsri: number\n gmi: number\n aqi: number\n sgi: number\n depi: number\n sgai: number\n lvgi: number\n tata: number\n }\n manipulationLikely: boolean\n interpretation: string\n}\n\nexport function beneishMScore(input: BeneishInput): BeneishResult | null {\n const { current: c, prior: p } = input\n\n if (p.revenue === 0 || p.totalAssets === 0 || p.grossProfit === 0) return null\n\n // DSRI: Days Sales Receivable Index\n const dsri = safeDivide(\n safeDivide(c.accountsReceivable, c.revenue),\n safeDivide(p.accountsReceivable, p.revenue)\n )\n // GMI: Gross Margin Index\n const gmi = safeDivide(\n safeDivide(p.grossProfit, p.revenue),\n safeDivide(c.grossProfit, c.revenue)\n )\n // AQI: Asset Quality Index\n const aqiCurrent = c.totalAssets > 0\n ? 1 - (c.accountsReceivable + c.ppGross + c.cashFlowFromOps) / c.totalAssets\n : null\n const aqiPrior = p.totalAssets > 0\n ? 1 - (p.accountsReceivable + p.ppGross) / p.totalAssets\n : null\n const aqi = safeDivide(aqiCurrent, aqiPrior)\n // SGI: Sales Growth Index\n const sgi = safeDivide(c.revenue, p.revenue)\n // DEPI: Depreciation Index\n const depiCurrent = c.ppGross > 0 ? c.depreciation / (c.depreciation + c.ppGross) : null\n const depiPrior = p.ppGross > 0 ? p.depreciation / (p.depreciation + p.ppGross) : null\n const depi = safeDivide(depiPrior, depiCurrent)\n // SGAI: SG&A Expense Index\n const sgai = safeDivide(\n safeDivide(c.sgaExpense, c.revenue),\n safeDivide(p.sgaExpense, p.revenue)\n )\n // LVGI: Leverage Index\n const lvgi = safeDivide(\n safeDivide(c.totalDebt, c.totalAssets),\n safeDivide(p.totalDebt, p.totalAssets)\n )\n // TATA: Total Accruals to Total Assets\n const tata = c.totalAssets > 0\n ? (c.netIncome - c.cashFlowFromOps) / c.totalAssets\n : null\n\n if (\n dsri == null || gmi == null || aqi == null || sgi == null ||\n depi == null || sgai == null || lvgi == null || tata == null\n ) return null\n\n const mScore =\n -4.84 +\n 0.92 * dsri +\n 0.528 * gmi +\n 0.404 * aqi +\n 0.892 * sgi +\n 0.115 * depi -\n 0.172 * sgai +\n 4.679 * tata -\n 0.327 * lvgi\n\n const manipulationLikely = mScore > -2.22\n\n return {\n mScore,\n variables: { dsri, gmi, aqi, sgi, depi, sgai, lvgi, tata },\n manipulationLikely,\n interpretation: manipulationLikely\n ? `M-Score ${mScore.toFixed(2)} > -2.22: Possible earnings manipulation`\n : `M-Score ${mScore.toFixed(2)} ≤ -2.22: No strong sign of manipulation`,\n }\n}\nbeneishMScore.formula = '-4.84 + 0.92×DSRI + 0.528×GMI + 0.404×AQI + 0.892×SGI + 0.115×DEPI - 0.172×SGAI + 4.679×TATA - 0.327×LVGI'\nbeneishMScore.description = 'Earnings manipulation detector. M-Score > -2.22 indicates likely manipulation.'\n\n// ── Greenblatt Magic Formula ───────────────────────────────────────────────────\n\nexport interface MagicFormulaResult {\n roic: number | null\n evEbit: number | null\n}\n\nexport function magicFormula(input: {\n ebit: number\n netWorkingCapital: number\n netFixedAssets: number\n enterpriseValue: number\n}): MagicFormulaResult {\n const tangibleCapital = input.netWorkingCapital + input.netFixedAssets\n return {\n roic: safeDivide(input.ebit, tangibleCapital),\n evEbit: safeDivide(input.enterpriseValue, input.ebit),\n }\n}\nmagicFormula.formula = 'ROIC = EBIT / (Net Working Capital + Net Fixed Assets); Earnings Yield = EBIT / EV'\nmagicFormula.description = 'Greenblatt\\'s Magic Formula: rank by ROIC + EV/EBIT. Best combo = buy.'\n\n// ── Ohlson O-Score ────────────────────────────────────────────────────────────\n\nexport interface OhlsonInput {\n totalAssets: number\n totalLiabilities: number\n currentAssets: number\n currentLiabilities: number\n netIncome: number\n priorNetIncome: number\n operatingCashFlow: number\n workingCapital: number\n gnp: number // GNP price level index, often approximated as 1\n}\n\nexport function ohlsonOScore(input: OhlsonInput): { oScore: number; bankruptcyProbability: number; interpretation: string } | null {\n if (input.totalAssets <= 0) return null\n\n const t1 = -1.32 - 0.407 * Math.log(input.totalAssets / input.gnp)\n const t2 = 6.03 * (input.totalLiabilities / input.totalAssets)\n const t3 = -1.43 * (input.workingCapital / input.totalAssets)\n const t4 = 0.0757 * (input.currentLiabilities / input.currentAssets)\n const t5 = input.totalLiabilities > input.totalAssets ? -1.72 * 1 : 0\n const t6 = -2.37 * (input.netIncome / input.totalAssets)\n const t7 = -1.83 * (input.operatingCashFlow / input.totalAssets)\n const t8 =\n 0.285 * ((input.netIncome + input.priorNetIncome < 0) ? 1 : 0)\n const t9 =\n -0.521 *\n safeDivide(\n input.netIncome - input.priorNetIncome,\n Math.abs(input.netIncome) + Math.abs(input.priorNetIncome)\n )!\n\n const oScore = t1 + t2 + t3 + t4 + t5 + t6 + t7 + t8 + t9\n const bankruptcyProbability = 1 / (1 + Math.exp(-oScore))\n\n return {\n oScore,\n bankruptcyProbability,\n interpretation: bankruptcyProbability > 0.5\n ? `High bankruptcy risk (${(bankruptcyProbability * 100).toFixed(1)}% probability)`\n : `Low bankruptcy risk (${(bankruptcyProbability * 100).toFixed(1)}% probability)`,\n }\n}\nohlsonOScore.formula = 'Logistic regression: -1.32 - 0.407*SIZE + 6.03*TLTA - 1.43*WCTA + 0.0757*CLCA ...'\nohlsonOScore.description = 'Bankruptcy prediction via logistic regression. Outputs probability 0-1.'\n\n// ── Montier C-Score ────────────────────────────────────────────────────────────\n\nexport interface MontierCInput {\n current: {\n netIncome: number\n operatingCashFlow: number\n accountsReceivable: number\n revenue: number\n inventory: number\n cogs: number\n cash: number\n totalAssets: number\n longTermDebt: number\n grossProfit: number\n }\n prior: {\n accountsReceivable: number\n revenue: number\n inventory: number\n cogs: number\n cash: number\n totalAssets: number\n longTermDebt: number\n grossProfit: number\n }\n}\n\nexport interface MontierCResult {\n score: number\n signals: {\n c1Accruals: boolean\n c2DsoIncreasing: boolean\n c3InventoryDaysIncreasing: boolean\n c4CashDeclining: boolean\n c5LeverageIncreasing: boolean\n c6GrossMarginDeclining: boolean\n }\n highRisk: boolean\n interpretation: string\n}\n\n/**\n * Montier C-Score (Earnings Quality / Creative Accounting Score).\n *\n * 6 binary signals — higher score = more red flags = lower earnings quality.\n *\n * Reference: Montier, J. (2008). Joining the Dark Side: Pirates, Spies and Short Sellers.\n * Société Générale Cross Asset Research.\n */\nexport function montierCScore(input: MontierCInput): MontierCResult {\n const { current: c, prior: p } = input\n\n // C1: Net income > Operating cash flow (accrual-based earnings)\n const c1Accruals = c.netIncome > c.operatingCashFlow\n\n // C2: Days sales outstanding increasing\n const dsoCurrent = c.revenue > 0 ? c.accountsReceivable / c.revenue : 0\n const dsoPrior = p.revenue > 0 ? p.accountsReceivable / p.revenue : 0\n const c2DsoIncreasing = dsoCurrent > dsoPrior\n\n // C3: Days inventory outstanding increasing\n const dioCurrent = c.cogs > 0 ? c.inventory / c.cogs : 0\n const dioPrior = p.cogs > 0 ? p.inventory / p.cogs : 0\n const c3InventoryDaysIncreasing = dioCurrent > dioPrior\n\n // C4: Cash declining as % of total assets\n const cashPctCurrent = c.totalAssets > 0 ? c.cash / c.totalAssets : 0\n const cashPctPrior = p.totalAssets > 0 ? p.cash / p.totalAssets : 0\n const c4CashDeclining = cashPctCurrent < cashPctPrior\n\n // C5: Long-term debt increasing as % of total assets\n const ltdPctCurrent = c.totalAssets > 0 ? c.longTermDebt / c.totalAssets : 0\n const ltdPctPrior = p.totalAssets > 0 ? p.longTermDebt / p.totalAssets : 0\n const c5LeverageIncreasing = ltdPctCurrent > ltdPctPrior\n\n // C6: Gross margin declining\n const gmCurrent = c.revenue > 0 ? c.grossProfit / c.revenue : 0\n const gmPrior = p.revenue > 0 ? p.grossProfit / p.revenue : 0\n const c6GrossMarginDeclining = gmCurrent < gmPrior\n\n const signals = {\n c1Accruals,\n c2DsoIncreasing,\n c3InventoryDaysIncreasing,\n c4CashDeclining,\n c5LeverageIncreasing,\n c6GrossMarginDeclining,\n }\n\n const score = Object.values(signals).filter(Boolean).length\n const highRisk = score >= 4\n\n let interpretation: string\n if (score <= 1) interpretation = `C-Score ${score}/6: High earnings quality — few red flags`\n else if (score <= 3) interpretation = `C-Score ${score}/6: Moderate concern — review signals carefully`\n else interpretation = `C-Score ${score}/6: Significant red flags — possible earnings management`\n\n return { score, signals, highRisk, interpretation }\n}\n\nmontierCScore.formula = '6 binary signals: accruals, DSO, inventory days, cash%, long-term debt%, gross margin'\nmontierCScore.description = 'Earnings quality score 0-6. Higher = more red flags. 4+ signals = high risk.'\n","/**\n * Batch compute all applicable ratios from a single financial data object.\n *\n * Usage:\n * import { computeAll } from 'fin-ratios'\n *\n * const data = await fetchYahoo('AAPL')\n * const ratios = computeAll(data)\n * console.log(ratios.pe) // 28.3\n * console.log(ratios.roic) // 0.55\n * console.log(ratios.altmanZ) // { zScore: 4.8, zone: 'safe', ... }\n */\n\nimport { safeDivide } from './safe-divide.js'\n\n// Import all ratio functions\nimport {\n pe, pb, ps, peg, pFcf, evEbitda, evEbit, evRevenue, evFcf, tobinsQ, grahamNumber,\n} from '../ratios/valuation/index.js'\nimport {\n grossMargin, operatingMargin, ebitdaMargin, netProfitMargin,\n roe, roa, nopat, roic, roce, investedCapital,\n} from '../ratios/profitability/index.js'\nimport {\n currentRatio, quickRatio, dso, dio, dpo, cashConversionCycle,\n} from '../ratios/liquidity/index.js'\nimport {\n debtToEquity, netDebtToEquity, netDebtToEbitda,\n debtToAssets, interestCoverageRatio, equityMultiplier,\n} from '../ratios/solvency/index.js'\nimport {\n assetTurnover, receivablesTurnover, inventoryTurnover, payablesTurnover,\n} from '../ratios/efficiency/index.js'\nimport {\n freeCashFlow, fcfYield, fcfMargin, fcfConversion, ocfToSales, capexToRevenue,\n} from '../ratios/cashflow/index.js'\nimport {\n altmanZScore, piotroskiFScore,\n} from '../ratios/composite/index.js'\n\n// ── Input type ────────────────────────────────────────────────────────────────\n\nexport interface FinancialData {\n // Income Statement\n revenue?: number\n grossProfit?: number\n ebit?: number\n ebitda?: number\n netIncome?: number\n interestExpense?: number\n incomeTaxExpense?: number\n ebt?: number\n cogs?: number\n // Balance Sheet\n totalAssets?: number\n totalEquity?: number\n totalDebt?: number\n currentAssets?: number\n currentLiabilities?: number\n cash?: number\n accountsReceivable?: number\n inventory?: number\n retainedEarnings?: number\n totalLiabilities?: number\n accountsPayable?: number\n longTermDebt?: number\n sharesOutstanding?: number\n // Cash Flow\n operatingCashFlow?: number\n capex?: number\n // Market\n marketCap?: number\n enterpriseValue?: number\n epsGrowthPct?: number\n // Prior period (for Piotroski)\n prior?: Omit<FinancialData, 'prior' | 'marketCap' | 'enterpriseValue' | 'epsGrowthPct'>\n}\n\n// ── Output type ───────────────────────────────────────────────────────────────\n\nexport interface RatioResults {\n // Valuation\n pe?: number | null\n pb?: number | null\n ps?: number | null\n peg?: number | null\n pFcf?: number | null\n enterpriseValue?: number | null\n evEbitda?: number | null\n evEbit?: number | null\n evRevenue?: number | null\n evFcf?: number | null\n tobinsQ?: number | null\n grahamNumber?: number | null\n // Profitability\n grossMargin?: number | null\n operatingMargin?: number | null\n netMargin?: number | null\n ebitdaMargin?: number | null\n roe?: number | null\n roa?: number | null\n roic?: number | null\n roce?: number | null\n nopat?: number | null\n investedCapital?: number | null\n // Cash Flow\n freeCashFlow?: number | null\n fcfMargin?: number | null\n fcfConversion?: number | null\n ocfToSales?: number | null\n capexToRevenue?: number | null\n fcfYield?: number | null\n // Liquidity\n currentRatio?: number | null\n quickRatio?: number | null\n dso?: number | null\n dio?: number | null\n dpo?: number | null\n cashConversionCycle?: number | null\n // Solvency\n debtToEquity?: number | null\n netDebtToEquity?: number | null\n netDebtToEbitda?: number | null\n debtToAssets?: number | null\n interestCoverage?: number | null\n equityMultiplier?: number | null\n // Efficiency\n assetTurnover?: number | null\n receivablesTurnover?: number | null\n inventoryTurnover?: number | null\n payablesTurnover?: number | null\n // Composite\n altmanZ?: ReturnType<typeof altmanZScore>\n piotroski?: ReturnType<typeof piotroskiFScore> | null\n}\n\n// ── Helper ────────────────────────────────────────────────────────────────────\n\nfunction g(data: FinancialData, key: keyof FinancialData): number {\n const v = data[key]\n if (v === undefined || v === null || typeof v === 'object') return 0\n return (v as number) || 0\n}\n\nfunction gn(data: FinancialData, key: keyof FinancialData): number | undefined {\n const v = data[key]\n if (v === undefined || v === null || typeof v === 'object') return undefined\n return (v as number) || undefined\n}\n\n// ── Main function ─────────────────────────────────────────────────────────────\n\n/**\n * Compute all applicable financial ratios from a data object.\n *\n * Returns a flat object with 40+ ratio values. Complex scores (Altman, Piotroski)\n * are nested objects. Returns undefined for unavailable ratios.\n *\n * @param data Financial data object with income/balance/cashflow/market fields\n * @returns Flat object of ratio name → value\n *\n * @example\n * const data = await fetchYahoo('AAPL')\n * const r = computeAll(data)\n * console.log(r.grossMargin) // 0.433\n * console.log(r.roic) // 0.55\n * console.log(r.altmanZ?.zone) // 'safe'\n */\nexport function computeAll(data: FinancialData): RatioResults {\n const result: RatioResults = {}\n\n const revenue = g(data, 'revenue')\n const grossProfit = g(data, 'grossProfit')\n const ebit = g(data, 'ebit')\n const ebitda = g(data, 'ebitda')\n const netIncome = g(data, 'netIncome')\n const totalAssets = g(data, 'totalAssets')\n const totalEquity = g(data, 'totalEquity')\n const totalDebt = g(data, 'totalDebt')\n const currentAssets = g(data, 'currentAssets')\n const currentLiabilities = g(data, 'currentLiabilities')\n const cash = g(data, 'cash')\n const accountsReceivable = g(data, 'accountsReceivable')\n const inventory = g(data, 'inventory')\n const marketCap = g(data, 'marketCap')\n const operatingCashFlow = g(data, 'operatingCashFlow')\n const capexRaw = g(data, 'capex')\n const interestExpense = g(data, 'interestExpense')\n const incomeTaxExpense = g(data, 'incomeTaxExpense')\n const ebt = g(data, 'ebt')\n const cogs = g(data, 'cogs')\n const accountsPayable = g(data, 'accountsPayable')\n const retainedEarnings = g(data, 'retainedEarnings')\n const totalLiabilities = g(data, 'totalLiabilities')\n const sharesOutstanding = g(data, 'sharesOutstanding')\n\n const fcf = freeCashFlow({ operatingCashFlow, capex: capexRaw })\n const ev = data.enterpriseValue || (marketCap + totalDebt - cash) || undefined\n\n const taxRate = ebt ? Math.min(Math.max(safeDivide(incomeTaxExpense, ebt) ?? 0.21, 0), 0.5) : 0.21\n const nopatVal = nopat({ ebit, taxRate })\n const icVal = investedCapital({ totalEquity, totalDebt, cash })\n\n // ── Valuation ───────────────────────────────────────────────────────────────\n result.pe = pe({ marketCap, netIncome })\n result.pb = pb({ marketCap, totalEquity })\n result.ps = ps({ marketCap, revenue })\n if (result.pe && data.epsGrowthPct) {\n result.peg = peg({ peRatio: result.pe, epsGrowthRatePercent: data.epsGrowthPct })\n }\n if (operatingCashFlow) result.pFcf = pFcf({ marketCap, operatingCashFlow, capex: capexRaw })\n result.enterpriseValue = ev ?? null\n if (ev && ebitda) result.evEbitda = evEbitda({ enterpriseValue: ev, ebitda })\n if (ev && ebit) result.evEbit = evEbit({ enterpriseValue: ev, ebit })\n if (ev && revenue) result.evRevenue = evRevenue({ enterpriseValue: ev, revenue })\n if (ev && fcf) result.evFcf = evFcf({ enterpriseValue: ev, freeCashFlow: fcf })\n result.tobinsQ = tobinsQ({ marketCap, totalDebt, totalAssets })\n if (sharesOutstanding) {\n const eps = safeDivide(netIncome, sharesOutstanding)\n const bvps = safeDivide(totalEquity, sharesOutstanding)\n if (eps && bvps) result.grahamNumber = grahamNumber({ eps, bookValuePerShare: bvps })\n }\n\n // ── Profitability ────────────────────────────────────────────────────────────\n result.grossMargin = grossMargin({ grossProfit, revenue })\n result.operatingMargin = operatingMargin({ ebit, revenue })\n result.netMargin = netProfitMargin({ netIncome, revenue })\n if (ebitda) result.ebitdaMargin = ebitdaMargin({ ebitda, revenue })\n result.roe = roe({ netIncome, avgTotalEquity: totalEquity })\n result.roa = roa({ netIncome, avgTotalAssets: totalAssets })\n result.nopat = nopatVal\n result.investedCapital = icVal\n if (nopatVal && icVal) result.roic = roic({ nopat: nopatVal, investedCapital: icVal })\n result.roce = roce({ ebit, totalAssets, currentLiabilities })\n\n // ── Cash Flow ────────────────────────────────────────────────────────────────\n result.freeCashFlow = fcf ?? null\n if (fcf) {\n result.fcfMargin = fcfMargin({ freeCashFlow: fcf, revenue })\n result.fcfConversion = fcfConversion({ freeCashFlow: fcf, netIncome })\n if (marketCap) result.fcfYield = fcfYield({ freeCashFlow: fcf, marketCap })\n }\n\n result.ocfToSales = ocfToSales({ operatingCashFlow, revenue })\n result.capexToRevenue = capexToRevenue({ capex: capexRaw, revenue })\n\n // ── Liquidity ────────────────────────────────────────────────────────────────\n result.currentRatio = currentRatio({ currentAssets, currentLiabilities })\n result.quickRatio = quickRatio({ cash, shortTermInvestments: 0, accountsReceivable, currentLiabilities })\n result.dso = dso({ accountsReceivable, revenue })\n if (cogs) {\n result.dio = dio({ inventory, cogs })\n result.dpo = dpo({ accountsPayable, cogs })\n }\n if (result.dso != null) {\n result.cashConversionCycle = cashConversionCycle({\n dso: result.dso,\n dio: result.dio ?? 0,\n dpo: result.dpo ?? 0,\n })\n }\n\n // ── Solvency ─────────────────────────────────────────────────────────────────\n result.debtToEquity = debtToEquity({ totalDebt, totalEquity })\n result.netDebtToEquity = netDebtToEquity({ totalDebt, cash, totalEquity })\n if (ebitda) result.netDebtToEbitda = netDebtToEbitda({ totalDebt, cash, ebitda })\n result.debtToAssets = debtToAssets({ totalDebt, totalAssets })\n result.interestCoverage = interestCoverageRatio({ ebit, interestExpense })\n result.equityMultiplier = equityMultiplier({ totalAssets, totalEquity })\n\n // ── Efficiency ───────────────────────────────────────────────────────────────\n result.assetTurnover = assetTurnover({ revenue, avgTotalAssets: totalAssets })\n result.receivablesTurnover = receivablesTurnover({ revenue, avgAccountsReceivable: accountsReceivable })\n if (cogs) {\n result.inventoryTurnover = inventoryTurnover({ cogs, avgInventory: inventory })\n result.payablesTurnover = payablesTurnover({ cogs, avgAccountsPayable: accountsPayable })\n }\n\n // ── Composite ────────────────────────────────────────────────────────────────\n if (totalAssets && totalLiabilities) {\n result.altmanZ = altmanZScore({\n workingCapital: currentAssets - currentLiabilities,\n retainedEarnings,\n ebit,\n marketCap,\n totalLiabilities,\n totalAssets,\n revenue,\n })\n }\n\n if (data.prior) {\n const p = data.prior\n const pGet = (key: keyof typeof p): number => {\n const v = p[key]\n return (typeof v === 'number' ? v : 0) || 0\n }\n try {\n result.piotroski = piotroskiFScore({\n current: {\n netIncome,\n totalAssets,\n operatingCashFlow,\n longTermDebt: g(data, 'longTermDebt'),\n currentAssets,\n currentLiabilities,\n sharesOutstanding,\n grossProfit,\n revenue,\n },\n prior: {\n netIncome: pGet('netIncome'),\n totalAssets: pGet('totalAssets'),\n longTermDebt: pGet('longTermDebt'),\n currentAssets: pGet('currentAssets'),\n currentLiabilities: pGet('currentLiabilities'),\n sharesOutstanding: pGet('sharesOutstanding'),\n grossProfit: pGet('grossProfit'),\n revenue: pGet('revenue'),\n },\n })\n } catch {\n result.piotroski = null\n }\n }\n\n return result\n}\n","/**\n * Scenario-based DCF valuation (bull / base / bear).\n *\n * Usage:\n * import { scenarioDcf } from 'fin-ratios'\n *\n * const result = scenarioDcf({\n * baseFcf: 100e9,\n * sharesOutstanding: 15.7e9,\n * currentPrice: 185,\n * scenarios: {\n * bear: { growthRate: 0.04, wacc: 0.12, terminalGrowth: 0.02, years: 10 },\n * base: { growthRate: 0.08, wacc: 0.09, terminalGrowth: 0.03, years: 10 },\n * bull: { growthRate: 0.14, wacc: 0.08, terminalGrowth: 0.04, years: 10 },\n * },\n * })\n *\n * console.log(result.base.intrinsicValuePerShare) // 198.75\n * console.log(result.base.upsidePct) // 0.074 (+7.4%)\n */\n\nimport { safeDivide } from './safe-divide.js'\n\n// ── Types ──────────────────────────────────────────────────────────────────────\n\nexport interface ScenarioParams {\n /** Annual FCF growth rate during projection period (e.g. 0.08 = 8%) */\n growthRate?: number\n /** Weighted average cost of capital / discount rate (e.g. 0.09 = 9%) */\n wacc?: number\n /** Terminal/perpetual growth rate after projection period (e.g. 0.02 = 2%) */\n terminalGrowth?: number\n /** Number of projection years (default: 10) */\n years?: number\n}\n\nexport interface ScenarioResult {\n /** Total equity intrinsic value */\n intrinsicValue: number\n /** Intrinsic value per diluted share */\n intrinsicValuePerShare: number | null\n /** PV of projected FCFs */\n pvFcfs: number\n /** PV of terminal value */\n pvTerminal: number\n /** Terminal value (undiscounted) */\n terminalValue: number\n /** Upside/downside vs current price (e.g. 0.07 = +7%) */\n upsidePct: number | null\n /** Input parameters used */\n params: Required<ScenarioParams>\n}\n\nexport interface ScenarioDcfInput {\n /** Most recent trailing FCF (absolute dollars, not per-share) */\n baseFcf: number\n /** Total diluted shares outstanding */\n sharesOutstanding: number\n /** Per-scenario parameters */\n scenarios?: Record<string, ScenarioParams>\n /** Optional ticker for display */\n ticker?: string\n /** Optional current market price per share for upside calculation */\n currentPrice?: number\n}\n\nexport type ScenarioDcfResult = Record<string, ScenarioResult>\n\nconst DEFAULT_SCENARIOS: Record<string, ScenarioParams> = {\n bear: { growthRate: 0.03, wacc: 0.12, terminalGrowth: 0.02, years: 10 },\n base: { growthRate: 0.07, wacc: 0.09, terminalGrowth: 0.02, years: 10 },\n bull: { growthRate: 0.12, wacc: 0.08, terminalGrowth: 0.03, years: 10 },\n}\n\n// ── Main function ──────────────────────────────────────────────────────────────\n\n/**\n * Compute scenario-based DCF intrinsic value (bull / base / bear).\n *\n * Each scenario projects FCFs for N years, then applies a Gordon Growth Model\n * terminal value. Results are discounted back to present value at the scenario WACC.\n *\n * @param input FCF, shares, optional current price, and per-scenario parameters\n * @returns Map of scenario name → ScenarioResult\n *\n * @example\n * const r = scenarioDcf({ baseFcf: 100e9, sharesOutstanding: 15.7e9 })\n * r.base.intrinsicValuePerShare // computed base case IV per share\n */\nexport function scenarioDcf(input: ScenarioDcfInput): ScenarioDcfResult {\n const {\n baseFcf,\n sharesOutstanding,\n currentPrice,\n scenarios = DEFAULT_SCENARIOS,\n } = input\n\n const result: ScenarioDcfResult = {}\n\n for (const [name, params] of Object.entries(scenarios)) {\n const growthRate = params.growthRate ?? 0.07\n const wacc = params.wacc ?? 0.09\n const terminalGrowth = params.terminalGrowth ?? 0.02\n const years = params.years ?? 10\n\n // Project FCFs and discount to PV\n let fcf = baseFcf\n let pvSum = 0\n for (let t = 1; t <= years; t++) {\n fcf = fcf * (1 + growthRate)\n pvSum += fcf / Math.pow(1 + wacc, t)\n }\n\n // Terminal value (Gordon Growth)\n let terminalValue = 0\n if (wacc > terminalGrowth) {\n const terminalFcf = fcf * (1 + terminalGrowth)\n terminalValue = terminalFcf / (wacc - terminalGrowth)\n }\n const pvTerminal = terminalValue / Math.pow(1 + wacc, years)\n\n const intrinsicValue = pvSum + pvTerminal\n const intrinsicValuePerShare = safeDivide(intrinsicValue, sharesOutstanding) ?? null\n\n let upsidePct: number | null = null\n if (currentPrice && currentPrice > 0 && intrinsicValuePerShare !== null) {\n upsidePct = (intrinsicValuePerShare - currentPrice) / currentPrice\n }\n\n result[name] = {\n intrinsicValue,\n intrinsicValuePerShare,\n pvFcfs: pvSum,\n pvTerminal,\n terminalValue,\n upsidePct,\n params: { growthRate, wacc, terminalGrowth, years },\n }\n }\n\n return result\n}\n","/**\n * React hooks for fin-ratios.\n *\n * Optional sub-path export: import from 'fin-ratios/hooks'\n *\n * NOTE: These hooks require React as a peer dependency.\n * They are designed for client-side use in React applications.\n *\n * Usage:\n * import { useRatios, useHealthScore, useRatioHistory } from 'fin-ratios/hooks'\n *\n * function StockCard({ ticker }) {\n * const { data, loading, error } = useRatios(ticker)\n * if (loading) return <Spinner />\n * if (error) return <Error message={error} />\n * return <div>P/E: {data?.pe?.toFixed(1)}</div>\n * }\n */\n\nimport { useState, useEffect, useRef, useCallback } from 'react'\nimport type { RatioResults, FinancialData } from '../utils/compute-all.js'\nimport { computeAll } from '../utils/compute-all.js'\nimport type { ScenarioDcfInput, ScenarioDcfResult } from '../utils/scenario-dcf.js'\nimport { scenarioDcf } from '../utils/scenario-dcf.js'\n\n// ── Types ──────────────────────────────────────────────────────────────────────\n\nexport interface UseRatiosState<T> {\n data: T | null\n loading: boolean\n error: string | null\n refetch: () => void\n}\n\nexport type FetcherFn<T> = (ticker: string) => Promise<T>\n\n// ── useRatios ─────────────────────────────────────────────────────────────────\n\n/**\n * Fetch and compute all financial ratios for a ticker.\n *\n * @param ticker Stock ticker (e.g. 'AAPL'). Pass null/undefined to skip.\n * @param fetcher Async function that fetches raw financial data. Must be\n * stable across renders (wrap in useCallback if needed).\n *\n * @example\n * import { fetchYahoo } from 'fin-ratios/fetchers/yahoo'\n *\n * const { data, loading, error } = useRatios('AAPL', fetchYahoo)\n * console.log(data?.grossMargin) // 0.433\n * console.log(data?.roic) // 0.55\n */\nexport function useRatios<TRaw extends FinancialData>(\n ticker: string | null | undefined,\n fetcher: FetcherFn<TRaw>,\n): UseRatiosState<RatioResults> {\n const [state, setState] = useState<UseRatiosState<RatioResults>>({\n data: null,\n loading: false,\n error: null,\n refetch: () => {},\n })\n\n const fetcherRef = useRef(fetcher)\n fetcherRef.current = fetcher\n\n const fetch = useCallback(() => {\n if (!ticker) return\n\n setState((s: UseRatiosState<RatioResults>) => ({ ...s, loading: true, error: null }))\n\n fetcherRef.current(ticker)\n .then((raw: TRaw) => {\n const ratios = computeAll(raw)\n setState({ data: ratios, loading: false, error: null, refetch: fetch })\n })\n .catch((err: unknown) => {\n const message = err instanceof Error ? err.message : String(err)\n setState((s: UseRatiosState<RatioResults>) => ({ ...s, loading: false, error: message }))\n })\n }, [ticker])\n\n useEffect(() => {\n fetch()\n }, [fetch])\n\n return { ...state, refetch: fetch }\n}\n\n// ── useRatio ──────────────────────────────────────────────────────────────────\n\n/**\n * Fetch a single named ratio for a ticker.\n *\n * @param ticker Stock ticker\n * @param ratio Ratio name (key of RatioResults)\n * @param fetcher Financial data fetcher function\n *\n * @example\n * const { data: pe } = useRatio('AAPL', 'pe', fetchYahoo)\n */\nexport function useRatio<TRaw extends FinancialData, K extends keyof RatioResults>(\n ticker: string | null | undefined,\n ratio: K,\n fetcher: FetcherFn<TRaw>,\n): UseRatiosState<RatioResults[K]> {\n const ratiosState = useRatios(ticker, fetcher)\n return {\n data: ratiosState.data ? ratiosState.data[ratio] ?? null : null,\n loading: ratiosState.loading,\n error: ratiosState.error,\n refetch: ratiosState.refetch,\n }\n}\n\n// ── useHealthScore ────────────────────────────────────────────────────────────\n\n/**\n * Simplified hook that returns a normalized health score (0–100) based on\n * the computed ratios. Clients provide their own scoring function.\n *\n * @param ticker Stock ticker\n * @param fetcher Financial data fetcher\n * @param scoreFn Custom function: (ratios: RatioResults) => number\n *\n * @example\n * const { data: score } = useHealthScore('AAPL', fetchYahoo, (r) => {\n * let s = 50\n * if (r.roic && r.roic > 0.15) s += 20\n * if (r.grossMargin && r.grossMargin > 0.4) s += 15\n * if (r.currentRatio && r.currentRatio > 2) s += 15\n * return Math.min(s, 100)\n * })\n */\nexport function useHealthScore<TRaw extends FinancialData>(\n ticker: string | null | undefined,\n fetcher: FetcherFn<TRaw>,\n scoreFn: (ratios: RatioResults) => number,\n): UseRatiosState<number> {\n const ratiosState = useRatios(ticker, fetcher)\n const score = ratiosState.data ? scoreFn(ratiosState.data) : null\n return {\n data: score,\n loading: ratiosState.loading,\n error: ratiosState.error,\n refetch: ratiosState.refetch,\n }\n}\n\n// ── useScenarioDcf ────────────────────────────────────────────────────────────\n\n/**\n * Compute scenario DCF analysis reactively.\n *\n * @param input ScenarioDcfInput (baseFcf, shares, currentPrice, scenarios)\n *\n * @example\n * const { data } = useScenarioDcf({\n * baseFcf: 100e9,\n * sharesOutstanding: 15.7e9,\n * currentPrice: 185,\n * })\n * console.log(data?.base.upsidePct) // 0.074\n */\nexport function useScenarioDcf(\n input: ScenarioDcfInput | null,\n): { data: ScenarioDcfResult | null } {\n const [data, setData] = useState<ScenarioDcfResult | null>(null)\n\n useEffect(() => {\n if (!input) {\n setData(null)\n return\n }\n setData(scenarioDcf(input))\n }, [\n input?.baseFcf,\n input?.sharesOutstanding,\n input?.currentPrice,\n ])\n\n return { data }\n}\n\n// ── useCompareRatios ──────────────────────────────────────────────────────────\n\n/**\n * Fetch and compare ratios for multiple tickers in parallel.\n *\n * @param tickers Array of ticker symbols\n * @param fetcher Financial data fetcher\n *\n * @example\n * const { data } = useCompareRatios(['AAPL', 'MSFT', 'GOOGL'], fetchYahoo)\n * console.log(data?.AAPL?.grossMargin) // 0.433\n * console.log(data?.MSFT?.grossMargin) // 0.695\n */\nexport function useCompareRatios<TRaw extends FinancialData>(\n tickers: string[],\n fetcher: FetcherFn<TRaw>,\n): UseRatiosState<Record<string, RatioResults>> {\n const [state, setState] = useState<UseRatiosState<Record<string, RatioResults>>>({\n data: null,\n loading: false,\n error: null,\n refetch: () => {},\n })\n\n const fetcherRef = useRef(fetcher)\n fetcherRef.current = fetcher\n\n const tickersKey = tickers.join(',')\n\n const fetch = useCallback(() => {\n if (!tickers.length) return\n\n setState((s: UseRatiosState<Record<string, RatioResults>>) => ({ ...s, loading: true, error: null }))\n\n Promise.allSettled(tickers.map(t => fetcherRef.current(t).then((raw: TRaw) => [t, computeAll(raw)] as const)))\n .then((results: PromiseSettledResult<readonly [string, RatioResults]>[]) => {\n const data: Record<string, RatioResults> = {}\n for (const result of results) {\n if (result.status === 'fulfilled') {\n const [ticker, ratios] = result.value\n data[ticker] = ratios\n }\n }\n setState({ data, loading: false, error: null, refetch: fetch })\n })\n .catch((err: unknown) => {\n const message = err instanceof Error ? err.message : String(err)\n setState((s: UseRatiosState<Record<string, RatioResults>>) => ({ ...s, loading: false, error: message }))\n })\n }, [tickersKey]) // eslint-disable-line react-hooks/exhaustive-deps\n\n useEffect(() => {\n fetch()\n }, [fetch])\n\n return { ...state, refetch: fetch }\n}\n"]}
|