Automate issuer overlay creation from ticker searches
This commit is contained in:
@@ -9,7 +9,7 @@ import {
|
||||
} from '@/lib/server/repos/company-financial-bundles';
|
||||
import type { FilingTaxonomySnapshotRecord } from '@/lib/server/repos/filing-taxonomy';
|
||||
|
||||
export function computeSourceSignature(snapshots: FilingTaxonomySnapshotRecord[]) {
|
||||
function computeSourceSignature(snapshots: FilingTaxonomySnapshotRecord[]) {
|
||||
return snapshots
|
||||
.map((snapshot) => `${snapshot.id}:${snapshot.updated_at}`)
|
||||
.sort((left, right) => left.localeCompare(right))
|
||||
|
||||
@@ -37,7 +37,7 @@ export function periodSorter(left: FinancialStatementPeriod, right: FinancialSta
|
||||
return left.id.localeCompare(right.id);
|
||||
}
|
||||
|
||||
export function isInstantPeriod(period: FinancialStatementPeriod) {
|
||||
function isInstantPeriod(period: FinancialStatementPeriod) {
|
||||
return period.periodStart === null;
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ function selectPrimaryPeriodFromSnapshot(
|
||||
candidates.map((period) => [period.id, coverageScore(coverageRows, period.id)])
|
||||
);
|
||||
|
||||
if (statement === 'balance') {
|
||||
if (statement === 'balance' || statement === 'equity') {
|
||||
return [...candidates].sort((left, right) => compareBalancePeriods(left, right, rowCoverage))[0] ?? null;
|
||||
}
|
||||
|
||||
@@ -238,6 +238,10 @@ export function surfaceToStatementKind(surfaceKind: FinancialSurfaceKind): Finan
|
||||
return 'balance';
|
||||
case 'cash_flow_statement':
|
||||
return 'cash_flow';
|
||||
case 'equity_statement':
|
||||
return 'equity';
|
||||
case 'disclosures':
|
||||
return 'disclosure';
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -417,7 +421,7 @@ export function buildLtmFaithfulRows(
|
||||
const sourceValues = slice.map((period) => sourceRow.values[period.id] ?? null);
|
||||
const sourceUnits = slice.map((period) => sourceRow.units[period.id] ?? null).filter((unit): unit is string => unit !== null);
|
||||
|
||||
row.values[ltmPeriod.id] = statement === 'balance'
|
||||
row.values[ltmPeriod.id] = statement === 'balance' || statement === 'equity'
|
||||
? sourceValues[sourceValues.length - 1] ?? null
|
||||
: aggregateValues(sourceValues);
|
||||
row.units[ltmPeriod.id] = sourceUnits[sourceUnits.length - 1] ?? null;
|
||||
|
||||
@@ -3,7 +3,7 @@ import type {
|
||||
FinancialUnit
|
||||
} from '@/lib/types';
|
||||
|
||||
export type IndustryTemplate =
|
||||
type IndustryTemplate =
|
||||
| 'internet_platforms'
|
||||
| 'software_saas'
|
||||
| 'semiconductors_industrial_auto';
|
||||
@@ -80,7 +80,7 @@ const KPI_REGISTRY: RegistryBundle = {
|
||||
tickerDefinitions: {}
|
||||
};
|
||||
|
||||
export function getTickerIndustryTemplate(ticker: string): IndustryTemplate | null {
|
||||
function getTickerIndustryTemplate(ticker: string): IndustryTemplate | null {
|
||||
return KPI_REGISTRY.tickerTemplates[ticker.trim().toUpperCase()] ?? null;
|
||||
}
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ export function buildDimensionBreakdown(
|
||||
return map.size > 0 ? Object.fromEntries(map.entries()) : null;
|
||||
}
|
||||
|
||||
export function cloneStandardizedRows(rows: StandardizedFinancialRow[]) {
|
||||
function cloneStandardizedRows(rows: StandardizedFinancialRow[]) {
|
||||
return rows.map((row) => ({
|
||||
...row,
|
||||
values: { ...row.values },
|
||||
@@ -116,7 +116,7 @@ export function buildLtmStandardizedRows(
|
||||
quarterlyRows: StandardizedFinancialRow[],
|
||||
quarterlyPeriods: FinancialStatementPeriod[],
|
||||
ltmPeriods: FinancialStatementPeriod[],
|
||||
statement: Extract<FinancialStatementKind, 'income' | 'balance' | 'cash_flow'>
|
||||
statement: Extract<FinancialStatementKind, 'income' | 'balance' | 'cash_flow' | 'equity' | 'disclosure'>
|
||||
) {
|
||||
const sortedQuarterlyPeriods = [...quarterlyPeriods].sort((left, right) => {
|
||||
return Date.parse(left.periodEnd ?? left.filingDate) - Date.parse(right.periodEnd ?? right.filingDate);
|
||||
@@ -141,7 +141,7 @@ export function buildLtmStandardizedRows(
|
||||
|
||||
const slice = sortedQuarterlyPeriods.slice(anchorIndex - 3, anchorIndex + 1);
|
||||
const sourceValues = slice.map((period) => source.values[period.id] ?? null);
|
||||
row.values[ltmPeriod.id] = statement === 'balance'
|
||||
row.values[ltmPeriod.id] = statement === 'balance' || statement === 'equity'
|
||||
? sourceValues[sourceValues.length - 1] ?? null
|
||||
: sumValues(sourceValues);
|
||||
row.resolvedSourceRowKeys[ltmPeriod.id] = source.formulaKey ? null : source.resolvedSourceRowKeys[slice[slice.length - 1]?.id ?? ''] ?? null;
|
||||
|
||||
@@ -64,6 +64,12 @@ export function buildTrendSeries(input: {
|
||||
return (input.statementRows ?? [])
|
||||
.filter((row) => row.key === 'operating_cash_flow' || row.key === 'free_cash_flow' || row.key === 'capital_expenditures')
|
||||
.map(toTrendSeriesRow);
|
||||
case 'equity_statement':
|
||||
return (input.statementRows ?? [])
|
||||
.filter((row) => row.key === 'total_equity' || row.key === 'retained_earnings' || row.key === 'common_stock_and_apic')
|
||||
.map(toTrendSeriesRow);
|
||||
case 'disclosures':
|
||||
return [];
|
||||
case 'ratios':
|
||||
return (input.ratioRows ?? [])
|
||||
.filter((row) => row.category === 'margins')
|
||||
|
||||
Reference in New Issue
Block a user