import {z} from 'zod' export type GetApiV1StocksTickerValuationMultiplesArgs = {ticker: string}; export type GetApiV1StocksTickerValuationMultiplesOptions = {baseUrl?: string | undefined, ApiKey?: string | undefined, fetch?: typeof fetch | undefined}; export const industryMultiplesDto = z.object({industry: z.string().nullable().optional(), companyCount: z.number().int().optional(), peerCompanyCount: z.number().int().optional(), sizeBanded: z.boolean().optional(), marketCapFloor: z.number().nullable().optional(), marketCapCeiling: z.number().nullable().optional(), evToRevenueCompanyCount: z.number().int().optional(), evToEbitCompanyCount: z.number().int().optional(), peCompanyCount: z.number().int().optional(), priceToSalesCompanyCount: z.number().int().optional(), priceToBookCompanyCount: z.number().int().optional(), priceToFfoCompanyCount: z.number().int().optional(), priceToAffoCompanyCount: z.number().int().optional(), evToAdjustedEbitdaCompanyCount: z.number().int().optional(), evToRevenueMedian: z.number().nullable().optional(), evToRevenueP25: z.number().nullable().optional(), evToRevenueP75: z.number().nullable().optional(), evToEbitMedian: z.number().nullable().optional(), evToEbitP25: z.number().nullable().optional(), evToEbitP75: z.number().nullable().optional(), peMedian: z.number().nullable().optional(), peP25: z.number().nullable().optional(), peP75: z.number().nullable().optional(), priceToSalesMedian: z.number().nullable().optional(), priceToSalesP25: z.number().nullable().optional(), priceToSalesP75: z.number().nullable().optional(), priceToBookMedian: z.number().nullable().optional(), priceToBookP25: z.number().nullable().optional(), priceToBookP75: z.number().nullable().optional(), priceToFfoMedian: z.number().nullable().optional(), priceToFfoP25: z.number().nullable().optional(), priceToFfoP75: z.number().nullable().optional(), priceToAffoMedian: z.number().nullable().optional(), priceToAffoP25: z.number().nullable().optional(), priceToAffoP75: z.number().nullable().optional(), evToAdjustedEbitdaMedian: z.number().nullable().optional(), evToAdjustedEbitdaP25: z.number().nullable().optional(), evToAdjustedEbitdaP75: z.number().nullable().optional()}); export const valuationMultiplesResponse = z.object({ticker: z.string().nullable().optional(), companyName: z.string().nullable().optional(), industry: z.string().nullable().optional(), marketCap: z.number().optional(), enterpriseValue: z.number().nullable().optional(), ttmRevenue: z.number().nullable().optional(), ttmEbit: z.number().nullable().optional(), ttmEpsDiluted: z.number().nullable().optional(), enterpriseValueBalanceSheetDate: z.string().nullable().optional(), ttmRevenueWindowEnd: z.string().nullable().optional(), ttmEbitWindowEnd: z.string().nullable().optional(), ttmEpsWindowEnd: z.string().nullable().optional(), bookValue: z.number().nullable().optional(), bookValueDate: z.string().nullable().optional(), evToRevenue: z.number().nullable().optional(), evToEbit: z.number().nullable().optional(), peRatio: z.number().nullable().optional(), priceToSales: z.number().nullable().optional(), priceToBook: z.number().nullable().optional(), peBasis: z.string().nullable().optional(), ttmCommonShareholderIncome: z.number().nullable().optional(), ttmCommonShareholderIncomeWindowEnd: z.string().nullable().optional(), priceToFfo: z.number().nullable().optional(), priceToAffo: z.number().nullable().optional(), ffoPerShare: z.number().nullable().optional(), affoPerShare: z.number().nullable().optional(), ffoBasis: z.string().nullable().optional(), affoBasis: z.string().nullable().optional(), ffoLabel: z.string().nullable().optional(), affoLabel: z.string().nullable().optional(), evToAdjustedEbitda: z.number().nullable().optional(), adjustedEbitda: z.number().nullable().optional(), adjustedEbitdaBasis: z.string().nullable().optional(), adjustedEbitdaLabel: z.string().nullable().optional(), industryContext: industryMultiplesDto.optional()}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * A company's current valuation multiples (EV/Revenue, EV/EBIT, P/E, Price/Sales and Price/Book on TTM figures and the latest tagged equity) with a peer median, quartiles, and the actual sample count for each ratio. The subject is excluded from its own peers; similar-size industry peers are used when the industry holds enough of them, else the rest of the industry. Diluted EPS is published only when it reconciles to income and diluted weighted shares on one effective split basis. REITs also carry P/FFO and P/AFFO, and any filer with a verified reconciliation carries EV over its own stated Adjusted EBITDA, from the company's SEC-stated reconciliation. A company whose inputs prove no ratio still answers with the figures it has and null ratios; only a company with no valuation input at all is 404. * * GET /v1/stocks/{ticker}/valuation-multiples */ export const getApiV1StocksTickerValuationMultiples = async (args: GetApiV1StocksTickerValuationMultiplesArgs, options?: GetApiV1StocksTickerValuationMultiplesOptions) => { const {baseUrl = "https://api.equibles.com", fetch: fetchFn = fetch, ApiKey} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (ApiKey !== undefined) headers.set('authorization', `Bearer ${ApiKey}`) const url = `${baseUrl.replace(/\/+$/, '')}/v1/stocks/${encodeURIComponent(String(args.ticker))}/valuation-multiples${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(valuationMultiplesResponse, await res.json()) };