Skip to content

Bring Your Own Data

All scoring and ratio functions accept plain Python dicts, dataclasses, or any object with matching attributes. No fetcher is required.

Data Shape

Each annual record should contain as many of the fields below as are available. All fields are optional — functions return None when required inputs are missing.

Python field names (snake_case)

Field Description
revenue Total revenue / net sales
gross_profit Revenue minus COGS
ebit Operating income (EBIT)
ebitda EBIT + D&A
net_income Net income attributable to shareholders
operating_cash_flow Cash from operations
capex Capital expenditures (positive number)
free_cash_flow OCF − capex (auto-computed if omitted)
total_assets Total assets
total_equity Shareholders' equity
total_debt Short + long term debt
cash Cash and cash equivalents
short_term_investments Marketable securities
accounts_receivable Trade receivables
inventory Inventory balance
accounts_payable Trade payables
current_assets Total current assets
current_liabilities Total current liabilities
depreciation D&A charged in the period
income_tax_expense Income taxes paid / accrued
ebt Earnings before taxes
interest_expense Interest charges
shares_outstanding Diluted shares outstanding
dividends_paid Cash dividends (positive number)
buybacks Share repurchases (positive number)
r_and_d Research & development expense
invested_capital IC override (else computed from equity + debt − cash)

TypeScript field names (camelCase)

Same names in camelCase: revenue, grossProfit, ebit, ebitda, netIncome, operatingCashFlow, capex, totalAssets, totalEquity, totalDebt, cash, accountsReceivable, inventory, accountsPayable, currentAssets, currentLiabilities, depreciation, incomeTaxExpense, ebt, interestExpense, sharesOutstanding, dividendsPaid, buybacks, rAndD.

Minimal Example

from fin_ratios.utils.investment_score import investment_score_from_series

# Provide oldest year first
annual_data = [
    {
        "revenue": 260e9, "gross_profit": 100e9, "ebit": 63e9,
        "net_income": 55e9, "operating_cash_flow": 70e9,
        "total_assets": 320e9, "total_equity": 65e9,
        "total_debt": 95e9, "cash": 35e9, "capex": 8e9,
        "depreciation": 11e9, "income_tax_expense": 14e9, "ebt": 69e9,
    },
    {
        "revenue": 275e9, "gross_profit": 106e9, "ebit": 67e9,
        "net_income": 57e9, "operating_cash_flow": 73e9,
        "total_assets": 310e9, "total_equity": 60e9,
        "total_debt": 98e9, "cash": 33e9, "capex": 9e9,
        "depreciation": 12e9, "income_tax_expense": 15e9, "ebt": 71e9,
    },
    {
        "revenue": 294e9, "gross_profit": 114e9, "ebit": 73e9,
        "net_income": 62e9, "operating_cash_flow": 80e9,
        "total_assets": 300e9, "total_equity": 62e9,
        "total_debt": 90e9, "cash": 30e9, "capex": 8e9,
        "depreciation": 12e9, "income_tax_expense": 16e9, "ebt": 77e9,
    },
]

score = investment_score_from_series(annual_data, pe_ratio=18.0)
print(f"{score.score}/100  [{score.grade}]  {score.conviction}")
import { investmentScoreFromSeries } from 'fin-ratios'

// Oldest year first
const annualData = [
  {
    revenue: 260e9, grossProfit: 100e9, ebit: 63e9,
    netIncome: 55e9, operatingCashFlow: 70e9,
    totalAssets: 320e9, totalEquity: 65e9,
    totalDebt: 95e9, cash: 35e9, capex: 8e9,
    depreciation: 11e9, incomeTaxExpense: 14e9, ebt: 69e9,
  },
  // ... more years
]

const score = investmentScoreFromSeries(annualData, { peRatio: 18.0 })
console.log(`${score.score}/100 [${score.grade}] ${score.conviction}`)

Using Dataclasses

from dataclasses import dataclass
from fin_ratios.utils.quality_score import quality_score_from_series

@dataclass
class AnnualReport:
    revenue: float
    ebit: float
    net_income: float
    operating_cash_flow: float
    total_assets: float
    total_equity: float
    total_debt: float
    cash: float
    capex: float
    depreciation: float
    income_tax_expense: float
    ebt: float

annual_data = [
    AnnualReport(revenue=300e9, ebit=75e9, net_income=65e9, ...),
    # ...
]

quality = quality_score_from_series(annual_data)

Individual Ratios

For individual ratio functions, pass values directly:

import fin_ratios as fr

# All ratios accept keyword arguments
pe  = fr.pe(market_cap=3e12, net_income=1e11)          # 30.0
roe = fr.roe(net_income=65e9, avg_total_equity=60e9)   # 1.08
fcf = fr.free_cash_flow(operating_cash_flow=80e9, capex=8e9)  # 72e9

Ordering Convention

Always pass annual_data oldest-first (ascending chronological order). All *_from_series functions expect index 0 to be the oldest year.

# Correct — oldest to newest
annual_data = [year_2020, year_2021, year_2022, year_2023]

# Wrong — newest first
annual_data = [year_2023, year_2022, year_2021, year_2020]

Fetchers from SEC EDGAR return data newest-first; reverse before passing to scoring utilities, or use the fetch_edgar helper which handles this automatically.