Session 4 of 26 Part II: Financial Analysis & Value Drivers — Chapter 4 of 18
Part II: Financial Analysis & Value Drivers Chapter 4 of 18 Session 4 Python Excel

Financial Ratio Analysis for Valuation

Compute, interpret, and automate four families of financial ratios — liquidity, solvency, profitability, and efficiency — to diagnose a company's financial health before you value it.

Learning Objectives

📋
Two Paths, One Destination — Choose Your Tool

This session computes four ratio families. The Python path (marked Python) automates them for any company; the parallel Excel path (green Excel Path boxes) computes the identical ratios with formulas — and one genuine advantage: Screener.in already reports many of these ratios (OPM, ROCE, Debt/Equity), so Excel users can cross-check their formulas against the website's pre-computed values. If your formula result matches Screener.in, your formula is right.

Python: ratio functions + peer comparison Excel: extend the Session 3 workbook

🔍 Opening Challenge — Doctor's Diagnosis

You are the financial doctor examining four patients. Each reports a different set of "vital signs":
Patient A: Current Ratio 0.6, Interest Coverage 4.5x
Patient B: Current Ratio 3.5, Debt-to-Equity 0.05, Gross Margin 45%
Patient C: Current Ratio 1.1, Interest Coverage 0.7x
Patient D: Current Ratio 2.0, Inventory Turnover 12x, Negative Cash Conversion Cycle
Your Task: Match each patient to a condition: (1) Distressed — can't cover interest, (2) Cash-rich IT company, (3) Retailer funded by suppliers, (4) Thin liquidity but manageable debt. Turn to a partner and justify your answers. You have 3 minutes.

4.1 Why Ratio Analysis Precedes Valuation

A ratio is simply one financial number divided by another. But that simplicity is deceptive. Ratios are the diagnostic toolkit of the valuation practitioner — they reveal a company's financial architecture, its competitive strengths, its vulnerabilities, and the sustainability of its earnings. Before you forecast a single number, you must understand the company through its ratios.

Ratio analysis serves three purposes in the valuation workflow:

  • Diagnosis: Identify strengths and weaknesses. Is the company drowning in debt? Is its profit margin expanding or shrinking? Are customers paying on time? Ratios answer these questions before you build a single forecast.
  • Benchmarking: Compare the company against its peers. A 12% operating margin sounds decent — until you discover the industry average is 22%. Ratios provide context.
  • Forecast foundation: Historical ratio trends inform your forecast assumptions. If the gross margin has been stable at 55–58% for five years, you need a compelling reason to forecast 65%.
  • We organize ratios into four families, each answering a different question about the business:

    FamilyQuestion AnsweredKey Users
    Liquidity RatiosCan the company pay its bills over the next 12 months?Creditors, suppliers, short-term lenders
    Solvency / Leverage RatiosCan the company survive over the long term? Is its debt load sustainable?Bondholders, banks, rating agencies
    Profitability RatiosHow efficiently does the company convert revenue into profit?Equity investors, analysts, management
    Efficiency / Activity RatiosHow well does the company manage its assets and working capital?Operations managers, private equity, lenders
    Your Turn — Which Ratio Family? ⏱ 2 min

    For each question, identify which ratio family answers it:

    1. "Can this company pay its suppliers in the next 6 months?" → ___
    2. "Is this company's debt load sustainable over a decade?" → ___
    3. "How much profit does this company make per rupee of sales?" → ___
    4. "How quickly does this company turn inventory into cash?" → ___
    Reveal answers

    1) Liquidity · 2) Solvency · 3) Profitability · 4) Efficiency.

    4.2 Liquidity Ratios: Can the Company Survive Tomorrow?

    Liquidity ratios measure a company's ability to meet its short-term obligations as they fall due. A company can be highly profitable on paper and still go bankrupt if it runs out of cash. Liquidity is about survival.

    4.2.1 Current Ratio

    Current Ratio = Current Assets / Current Liabilities

    The current ratio is the broadest liquidity measure. A ratio of 2.0 means the company has Rs. 2 of current assets for every Rs. 1 of current liabilities. The traditional rule of thumb is 2.0, but this varies enormously by industry:

    Red Flag: A current ratio below 1.0 means current liabilities exceed current assets — the company technically cannot pay all its short-term obligations if they were called at once. While this can be normal for some business models (retail, FMCG), it warrants investigation in capital-intensive industries.

    4.2.2 Quick Ratio (Acid Test)

    Quick Ratio = (Current Assets − Inventory) / Current Liabilities

    The quick ratio strips out inventory — the least liquid current asset. It answers: if all sales stopped tomorrow, could the company pay its immediate bills? A quick ratio below 1.0 is a warning sign except in industries where inventory turns rapidly (FMCG, retail). For a steel company, however, a quick ratio of 0.4 signals potential distress — steel inventory cannot be liquidated quickly at book value.

    4.2.3 Cash Ratio

    Cash Ratio = (Cash + Marketable Securities) / Current Liabilities

    The most conservative liquidity measure. It asks: can the company pay all its short-term obligations with cash on hand alone? Most healthy companies have a cash ratio well below 1.0 — they do not keep idle cash equal to all their current liabilities. A very high cash ratio (above 1.5) may indicate poor capital allocation — money sitting in low-yield bank accounts rather than being invested in the business or returned to shareholders.

    4.2.4 Python Implementation

    def compute_liquidity_ratios(balance_sheet):
        """
        Compute current, quick, and cash ratios from balance sheet data.
    
        Parameters
        ----------
        balance_sheet : pd.DataFrame
            yfinance balance_sheet (columns = fiscal years)
        """
        def safe_get(df, candidates):
            for c in ([candidates] if isinstance(candidates, str) else candidates):
                if c in df.index:
                    return df.loc[c]
            return None
    
        current_assets = safe_get(balance_sheet, [
            'Current Assets', 'Total Current Assets'])
        current_liabilities = safe_get(balance_sheet, [
            'Current Liabilities', 'Total Current Liabilities'])
        inventory = safe_get(balance_sheet, ['Inventory', 'Inventories'])
        cash = safe_get(balance_sheet, [
            'Cash And Cash Equivalents',
            'Cash Cash Equivalents And Short Term Investments'])
    
        ratios = {}
    
        if current_assets is not None and current_liabilities is not None:
            ratios['Current Ratio'] = (current_assets / current_liabilities).round(2)
    
        if current_assets is not None and inventory is not None and current_liabilities is not None:
            ratios['Quick Ratio'] = ((current_assets - inventory) / current_liabilities).round(2)
    
        if cash is not None and current_liabilities is not None:
            ratios['Cash Ratio'] = (cash / current_liabilities).round(2)
    
        return pd.DataFrame(ratios)
    
    # Usage
    import yfinance as yf
    ticker = yf.Ticker("ASIANPAINT.NS")
    liquidity = compute_liquidity_ratios(ticker.balance_sheet)
    print(liquidity)
    Your Turn — Compute the Liquidity Ratios ⏱ 3 min

    Given this balance sheet snapshot (Rs. Cr):

    • Cash: 50 · Receivables: 120 · Inventory: 180
    • Current Liabilities: 250

    Compute all three liquidity ratios:

    • Current Ratio = ?
    • Quick Ratio = ?
    • Cash Ratio = ?

    Interpret: Is this company comfortably liquid? Which ratio reveals the concern?

    Reveal answers

    Current = (50+120+180)/250 = 1.4 · Quick = (50+120)/250 = 0.68 · Cash = 50/250 = 0.20. The current ratio looks OK, but the quick ratio of 0.68 reveals heavy dependence on inventory being sold — a concern if sales slow.

    X Excel Path — Liquidity Ratios as Three Formulas Excel

    On each company's Drivers sheet (Session 3 workbook), add three rows below your balance sheet items. Assume: Current Assets in row 20, Inventory in row 22, Cash in row 6, Current Liabilities in row 21 (adjust to your layout):

    ' Current Ratio (row 30):
    = C20 / C21
    ' Quick Ratio — subtract inventory (row 31):
    = (C20 - C22) / C21
    ' Cash Ratio (row 32):
    = C6 / C21
    ' Wrap all in IFERROR to survive missing data:
    =IFERROR(C20/C21, "n/a")

    Enter in the newest-year column, drag right for history — you now have the 5-year liquidity trend the Python function produces. Then repeat on every company sheet.

    Screener.in cross-check: the site's Balance Sheet table shows Current Assets and Current Liabilities directly — verify one year of your Current Ratio by hand against these two numbers.

    4.3 Solvency / Leverage Ratios: Can the Company Survive the Long Term?

    Solvency ratios measure a company's ability to meet its long-term debt obligations. While liquidity is about the next 12 months, solvency is about the next decade. High leverage magnifies returns in good times — and magnifies losses in bad times.

    4.3.1 Debt-to-Equity Ratio

    Debt-to-Equity = Total Debt / Shareholders' Equity

    This is the most widely used leverage ratio. A D/E of 1.0 means the company has equal amounts of debt and equity financing. Indian companies tend to have higher D/E ratios than their US counterparts due to historically higher interest rates making equity financing expensive, and promoter preference for retaining control through debt rather than equity dilution.

    Indian sector benchmarks:

    SectorTypical D/E RangeNotes
    IT Services0.0–0.2Asset-light, cash-rich — TCS and Infosys are virtually debt-free
    FMCG / Consumer0.0–0.5Strong cash flows; little need for debt financing
    Pharma0.2–0.8R&D and acquisitions drive debt; Sun Pharma ~0.3, Dr. Reddy's ~0.15
    Automotive0.5–1.5Capital-intensive; Tata Motors carries significant JLR debt
    Telecom1.5–3.0+Spectrum costs and infrastructure drive high leverage; Bharti Airtel ~2.0
    Infrastructure / Power2.0–5.0+Project finance model; high leverage is structural, not necessarily distressed

    4.3.2 Interest Coverage Ratio (ICR)

    Interest Coverage Ratio = EBIT / Interest Expense

    ICR measures how many times the company can pay its interest obligations from its operating profit. It is arguably more important than D/E because it directly answers the question: can the company service its debt?

    ⚡ Quick Think (30 seconds): An Indian telecom company has an Interest Coverage Ratio of 0.3 — its operating profit covers less than one-third of its interest bill. It owes the government billions in spectrum fees. What do you think happens next? Write down one prediction, then read the real-world example below.
    🌎
    Real World — Vodafone Idea: As of FY2024, Vodafone Idea had an interest coverage ratio below 0.3, meaning its operating profit covered less than one-third of its interest obligations. The company survived through government relief (converting interest dues to equity) and equity dilution. The ICR told the story long before the restructuring was announced — it was mathematically impossible for the company to service its debt from operations.

    4.3.3 Debt-to-EBITDA

    Debt-to-EBITDA = Total Debt / EBITDA

    This ratio measures how many years of EBITDA it would take to pay off all the debt, assuming EBITDA could be entirely devoted to debt repayment. A ratio above 4–5x is generally considered aggressive. Private equity firms routinely model this ratio as a key covenant metric.

    4.3.4 Python Implementation

    def compute_solvency_ratios(balance_sheet, income_stmt):
        """Compute debt-to-equity, interest coverage, and debt-to-EBITDA."""
        def safe_get(df, candidates):
            for c in ([candidates] if isinstance(candidates, str) else candidates):
                if c in df.index:
                    return df.loc[c]
            return None
    
        total_debt = safe_get(balance_sheet, ['Total Debt', 'Long Term Debt'])
        equity = safe_get(balance_sheet, [
            'Total Equity Gross Minority Interest',
            'Stockholders Equity', 'Total Equity'])
        ebit = safe_get(income_stmt, ['Operating Income', 'EBIT'])
        interest_expense = safe_get(income_stmt, ['Interest Expense',
                                                   'Interest Expense Non Operating'])
        ebitda = safe_get(income_stmt, ['EBITDA'])
    
        # If EBITDA not directly available, estimate
        if ebitda is None and ebit is not None:
            depreciation = safe_get(income_stmt, [
                'Depreciation And Amortization',
                'Depreciation Amortization Depletion'])
            if depreciation is not None:
                ebitda = ebit + depreciation
    
        ratios = {}
    
        if total_debt is not None and equity is not None:
            ratios['Debt-to-Equity'] = (total_debt / equity).round(2)
    
        if ebit is not None and interest_expense is not None:
            # Avoid division by zero
            icr = ebit / interest_expense.replace(0, np.nan)
            ratios['Interest Coverage'] = icr.round(2)
    
        if total_debt is not None and ebitda is not None:
            ratios['Debt-to-EBITDA'] = (total_debt / ebitda).round(2)
    
        return pd.DataFrame(ratios)
    Your Turn — Compute ICR and Diagnose ⏱ 3 min

    Compute the Interest Coverage Ratio for each company and classify its financial health:

    CompanyEBIT (Rs. Cr)Interest Expense (Rs. Cr)
    Alpha Industries40080
    Beta Infra200240
    Gamma Retail9060

    For each: (a) ICR = ? (b) Comfortable / Manageable / Stressed / Crisis?

    Reveal answers

    Alpha: ICR 5.0 → Comfortable. Beta: ICR 0.83 → Crisis (can't cover interest). Gamma: ICR 1.5 → Stressed. Beta is the Vodafone-Idea pattern — borrowing to pay interest.

    X Excel Path — Solvency Ratios + a Traffic-Light Rule Excel

    Same workbook, three more rows. Assume: Operating Profit row 3, Interest cost row 24 (Screener.in P&L line), Total Debt row 5, Equity row 7, EBITDA row 25:

    ' Debt-to-Equity (row 33):
    = C5 / C7
    ' Interest Coverage (row 34) — Excel's IF replaces our Python if/else:
    =IF(C24=0, "No debt", C3 / C24)
    ' Debt-to-EBITDA (row 35):
    =IFERROR(C5 / C25, "n/a")

    Bonus — the traffic light (conditional formatting): select the ICR row → Home → Conditional Formatting → Highlight Cell Rules → Less Than 1 → red fill. Add a second rule: Greater Than 5 → green fill. Now distress jumps off the sheet in color — the Excel equivalent of the classification table above, applied automatically to every company and year.

    Screener.in cross-check: the "Debt / Equity" ratio is printed on every company page — your row 33 should match it.

    4.4 Profitability Ratios: How Much Money Does the Business Actually Make?

    Profitability ratios measure a company's ability to generate profit relative to its revenue, assets, and equity. They are the most directly valuation-relevant family of ratios because profit generation is the engine that drives free cash flow.

    4.4.1 Margin Ratios

    We introduced margins in Chapters 2 and 3. Here we formalize them into a unified framework and add the interpretation layer.

    RatioFormulaWhat It Reveals
    Gross Margin(Revenue − COGS) / RevenuePricing power and production efficiency. Declining gross margins signal competitive pressure or rising input costs that cannot be passed on to customers.
    Operating MarginEBIT / RevenueThe profitability of the core business before financing and tax decisions. The single most important margin for DCF — it feeds directly into free cash flow projections.
    Net MarginNet Income / RevenueWhat ultimately accrues to shareholders. But it is contaminated by financing choices, tax planning, and non-operating items. Use with caution.
    EBITDA MarginEBITDA / RevenueA proxy for operating cash flow margin. Wide EBITDA margins (>30%) indicate a capital-light, high-pricing-power business.

    4.4.2 Return Ratios

    While margins measure profit per rupee of revenue, return ratios measure profit per rupee of investment. For valuation, return ratios are more important than margins because they capture capital efficiency.

    Return on Assets (ROA):

    ROA = Net Income / Total Assets

    ROA measures how efficiently the company uses its total asset base to generate profit. ROA varies dramatically by business model: an IT services company with minimal physical assets might show 15–20% ROA, while a steel manufacturer with massive PPE might show 3–5%. Comparing ROA across sectors is meaningless; comparing ROA within a sector identifies the most asset-efficient operators.

    Return on Equity (ROE):

    ROE = Net Income / Shareholders' Equity

    ROE measures the return earned on shareholders' capital. It is the most watched profitability metric by equity investors. However, ROE can be inflated by leverage — a company can boost ROE simply by taking on more debt. This is the DuPont effect.

    4.4.3 The DuPont Decomposition

    The DuPont formula decomposes ROE into three drivers, revealing why ROE is high or low:

    ROE = (Net Income / Revenue) × (Revenue / Total Assets) × (Total Assets / Equity)
    ROE = Net Margin × Asset Turnover × Equity Multiplier

    This decomposition is invaluable for valuation. A company with a 25% ROE achieved through a 20% net margin and low leverage (Titan) is fundamentally higher quality than a company with a 25% ROE achieved through a 5% margin and 5x leverage (an infrastructure developer). The former's earnings are sustainable; the latter's are fragile.

    4.4.4 Python Implementation

    def compute_profitability_ratios(income_stmt, balance_sheet):
        """Compute margins, ROA, ROE, and DuPont decomposition."""
        def safe_get(df, candidates):
            for c in ([candidates] if isinstance(candidates, str) else candidates):
                if c in df.index:
                    return df.loc[c]
            return None
    
        rev = safe_get(income_stmt, ['Total Revenue', 'Revenue'])
        gp  = safe_get(income_stmt, ['Gross Profit'])
        ebit = safe_get(income_stmt, ['Operating Income', 'EBIT'])
        ni  = safe_get(income_stmt, ['Net Income', 'Net Income Common Stockholders'])
        ebitda = safe_get(income_stmt, ['EBITDA'])
        assets = safe_get(balance_sheet, ['Total Assets'])
        equity = safe_get(balance_sheet, [
            'Total Equity Gross Minority Interest',
            'Stockholders Equity', 'Total Equity'])
    
        ratios = {}
    
        if gp is not None and rev is not None:
            ratios['Gross Margin (%)'] = (gp / rev * 100).round(2)
        if ebit is not None and rev is not None:
            ratios['Operating Margin (%)'] = (ebit / rev * 100).round(2)
        if ni is not None and rev is not None:
            ratios['Net Margin (%)'] = (ni / rev * 100).round(2)
        if ebitda is not None and rev is not None:
            ratios['EBITDA Margin (%)'] = (ebitda / rev * 100).round(2)
        if ni is not None and assets is not None:
            ratios['ROA (%)'] = (ni / assets * 100).round(2)
        if ni is not None and equity is not None:
            ratios['ROE (%)'] = (ni / equity * 100).round(2)
    
        # DuPont decomposition
        if ni is not None and rev is not None and assets is not None and equity is not None:
            net_margin = ni / rev
            asset_turnover = rev / assets
            equity_multiplier = assets / equity
            ratios['DuPont — Net Margin'] = (net_margin * 100).round(2)
            ratios['DuPont — Asset Turnover'] = asset_turnover.round(2)
            ratios['DuPont — Equity Multiplier'] = equity_multiplier.round(2)
    
        return pd.DataFrame(ratios)
    Your Turn — Decompose the ROE ⏱ 3 min

    Two companies both have ROE of 20%. Use the DuPont formula to see WHY:

    Company XCompany Y
    Net Margin15%5%
    Asset Turnover1.02.0
    Equity Multiplier1.332.0

    Compute each company's ROE. Then discuss with your partner: Which company's 20% ROE is more sustainable — and why?

    Reveal

    X: 15% × 1.0 × 1.33 ≈ 20%. Y: 5% × 2.0 × 2.0 = 20%. Company X's ROE comes from pricing power (high margin); Y's is inflated by leverage (multiplier 2.0). X's is more sustainable — Y's is fragile if rates rise.

    👥 Think-Pair-Share — The Leverage Illusion ⏱ 3 min

    Think: A company boosts its ROE from 15% to 22% purely by taking on more debt (higher equity multiplier). Has it actually become a better business?

    Pair: Discuss — is the higher ROE "real"? What risk is being added? What happens to ROE if interest rates rise?

    Share: We'll hear from 2 pairs. Key insight: leverage inflates ROE but adds risk — this is why valuation analysts compare ROE alongside D/E.

    X Excel Path — Margins, Returns, and the DuPont Decomposition Excel

    Margins and returns (rows 36–40; Net Profit row 4, Sales row 2, Total Assets row 8, Equity row 7):

    ' Net Margin % (row 36):
    = C4 / C2 * 100
    ' Return on Assets % (row 37):
    = C4 / C8 * 100
    ' Return on Equity % (row 38):
    = C4 / C7 * 100

    DuPont — build it as three visible rows that multiply into ROE (this is where Excel beats Python for learning, because you SEE the decomposition):

    ' DuPont 1: Net Margin (row 39) — as a decimal:
    = C4 / C2
    ' DuPont 2: Asset Turnover (row 40):
    = C2 / C8
    ' DuPont 3: Equity Multiplier (row 41):
    = C8 / C7
    ' ROE check (row 42) — should equal row 38 ÷ 100:
    = C39 * C40 * C41

    If row 42 ≠ row 38/100 to the 4th decimal, one of your references is wrong — this built-in check is your unit test.

    Screener.in cross-check: OPM appears at the top of the P&L table and ROE in the ratios panel — two free validation points for every company.

    4.5 Efficiency / Activity Ratios: How Well Is the Company Managed?

    Efficiency ratios measure how effectively a company uses its assets and manages its working capital. Two companies with identical margins can have vastly different free cash flows if one ties up twice as much capital in receivables and inventory.

    4.5.1 Asset Turnover

    Asset Turnover = Revenue / Total Assets

    This is the broadest efficiency measure. It answers: how many rupees of revenue does the company generate for each rupee of assets? An asset turnover of 2.0 means Rs. 2 of revenue per Rs. 1 of assets. Asset-light businesses (IT services, consulting) have high turnover (1.5–3.0); asset-heavy businesses (steel, power) have low turnover (0.3–0.8).

    4.5.2 Working Capital Ratios

    These three ratios form the cash conversion cycle — the time between paying suppliers and collecting from customers:

    RatioFormulaInterpretation
    Receivable Turnover Revenue / Accounts Receivable How many times per year the company collects its receivables. Higher = faster collection.
    Days Sales Outstanding (DSO) 365 / Receivable Turnover Average days to collect from customers. DSO > 90 days is concerning for most industries. Indian PSUs often have DSOs of 120–180 days due to government payment cycles.
    Inventory Turnover COGS / Inventory How many times per year inventory is sold. Higher = faster-moving inventory.
    Days Inventory Outstanding (DIO) 365 / Inventory Turnover Average days inventory sits before being sold. Rising DIO suggests slowing sales or obsolete stock.
    Payable Turnover COGS / Accounts Payable How many times per year the company pays suppliers.
    Days Payable Outstanding (DPO) 365 / Payable Turnover Average days to pay suppliers. A high DPO is good for cash flow (you are using supplier credit) but may signal strained supplier relationships.

    4.5.3 The Cash Conversion Cycle

    Cash Conversion Cycle = DSO + DIO − DPO

    The CCC measures how many days of working capital financing are needed to run the business. A negative CCC means the company collects from customers before it pays suppliers — it is effectively financed by its suppliers. This is the holy grail of working capital management. DMart (Avenue Supermarts) consistently runs a negative CCC because it collects cash from customers instantly but pays suppliers on 30–45 day terms.

    4.5.4 Python Implementation

    def compute_efficiency_ratios(income_stmt, balance_sheet):
        """Compute asset turnover and working capital efficiency ratios."""
        def safe_get(df, candidates):
            for c in ([candidates] if isinstance(candidates, str) else candidates):
                if c in df.index:
                    return df.loc[c]
            return None
    
        rev = safe_get(income_stmt, ['Total Revenue', 'Revenue'])
        cogs = safe_get(income_stmt, ['Cost Of Goods Sold', 'Cost of Revenue'])
        assets = safe_get(balance_sheet, ['Total Assets'])
        ar = safe_get(balance_sheet, ['Accounts Receivable',
                                       'Net Receivables', 'Receivables'])
        inv = safe_get(balance_sheet, ['Inventory', 'Inventories'])
        ap = safe_get(balance_sheet, ['Accounts Payable', 'Payables'])
    
        ratios = {}
    
        if rev is not None and assets is not None:
            ratios['Asset Turnover'] = (rev / assets).round(2)
    
        if rev is not None and ar is not None:
            ratios['Receivable Turnover'] = (rev / ar).round(2)
            ratios['Days Sales Outstanding'] = (365 / ratios['Receivable Turnover']).round(0)
    
        if cogs is not None and inv is not None:
            ratios['Inventory Turnover'] = (cogs / inv).round(2)
            ratios['Days Inventory Outstanding'] = (365 / ratios['Inventory Turnover']).round(0)
    
        if cogs is not None and ap is not None:
            ratios['Payable Turnover'] = (cogs / ap).round(2)
            ratios['Days Payable Outstanding'] = (365 / ratios['Payable Turnover']).round(0)
    
        # Cash Conversion Cycle
        if all(k in ratios for k in ['Days Sales Outstanding',
                                       'Days Inventory Outstanding',
                                       'Days Payable Outstanding']):
            ratios['Cash Conversion Cycle'] = (
                ratios['Days Sales Outstanding'] +
                ratios['Days Inventory Outstanding'] -
                ratios['Days Payable Outstanding'])
    
        return pd.DataFrame(ratios)
    Your Turn — Compute the Cash Conversion Cycle ⏱ 3 min

    For two retailers:

    DaysDMart-styleTypical Retailer
    Days Sales Outstanding215
    Days Inventory Outstanding2860
    Days Payable Outstanding4530

    Compute CCC = DSO + DIO − DPO for both. Which company is financed by its suppliers? What does a negative CCC mean?

    Reveal answers

    DMart: 2 + 28 − 45 = −15 days (negative — collects from customers before paying suppliers). Typical: 15 + 60 − 30 = 45 days. DMart needs no working capital — a huge competitive advantage.

    X Excel Path — Days Ratios and the Cash Conversion Cycle Excel

    Working capital items needed: Receivables row 26, Inventory row 22, Payables row 27, plus Sales (row 2) and COGS — if your Data sheet lacks a COGS row, add it from Screener.in's P&L ("Raw material cost" + "Other expenses" is a common approximation; use "Total Expenses" − "Employee cost" if needed):

    ' Days Sales Outstanding (row 43):
    = 365 * C26 / C2
    ' Days Inventory Outstanding (row 44):
    = 365 * C22 / COGS_cell
    ' Days Payable Outstanding (row 45):
    = 365 * C27 / COGS_cell
    ' Cash Conversion Cycle (row 46):
    = C43 + C44 - C45

    Why 365 ×: the formula 365 × (Receivables / Sales) is just "days = 365 ÷ turnover" rearranged — identical to the Python version, easier to audit in a cell.

    Instant benchmark: apply conditional formatting to the CCC row: Less Than 0 → green (supplier-financed business, the DMart pattern). Now scan all your companies' CCC rows at once — the negative ones glow.

    4.6 The Complete Ratio Analysis Pipeline

    Now we combine all four ratio families into a single, comprehensive analysis function that produces a complete financial diagnostic for any company:

    def full_ratio_analysis(ticker_symbol):
        """
        Perform a complete financial ratio analysis for any company.
    
        Returns a dict with four DataFrames (liquidity, solvency,
        profitability, efficiency) plus the latest-year summary.
        """
        ticker = yf.Ticker(ticker_symbol)
        info = ticker.info
        is_df = ticker.financials
        bs_df = ticker.balance_sheet
        cf_df = ticker.cashflow
    
        results = {
            'ticker': ticker_symbol,
            'company': info.get('longName', ticker_symbol),
            'sector': info.get('sector', 'N/A'),
            'market_cap': info.get('marketCap', None),
            'liquidity': compute_liquidity_ratios(bs_df),
            'solvency': compute_solvency_ratios(bs_df, is_df),
            'profitability': compute_profitability_ratios(is_df, bs_df),
            'efficiency': compute_efficiency_ratios(is_df, bs_df),
        }
    
        # Build a single-row summary (latest year)
        summary = {}
        for family in ['liquidity', 'solvency', 'profitability', 'efficiency']:
            df = results[family]
            if not df.empty:
                latest_col = df.columns[0]
                for idx in df.index:
                    summary[idx] = df.loc[idx, latest_col]
    
        results['summary'] = pd.Series(summary).round(2)
    
        return results
    
    
    def compare_ratios(tickers, labels=None):
        """Compare ratio summaries across multiple companies."""
        if labels is None:
            labels = [t.replace('.NS', '').replace('.BO', '') for t in tickers]
    
        summaries = {}
        for ticker, label in zip(tickers, labels):
            try:
                r = full_ratio_analysis(ticker)
                summaries[label] = r['summary']
                print(f"✓ {label}")
            except Exception as e:
                print(f"✗ {label}: {e}")
            time.sleep(1.5)
    
        return pd.DataFrame(summaries)
    
    
    # --- Example: Compare Indian consumer companies ---
    consumer_tickers = ['ASIANPAINT.NS', 'TITAN.NS', 'NESTLEIND.NS', 'BRITANNIA.NS']
    consumer_labels = ['Asian Paints', 'Titan', 'Nestle India', 'Britannia']
    
    comparison = compare_ratios(consumer_tickers, consumer_labels)
    
    # Display only key metrics
    key_metrics = [
        'Current Ratio', 'Debt-to-Equity', 'Interest Coverage',
        'Gross Margin (%)', 'Operating Margin (%)', 'Net Margin (%)',
        'ROE (%)', 'Asset Turnover', 'Cash Conversion Cycle'
    ]
    print("\n=== Indian Consumer Sector — Key Ratio Comparison ===")
    print(comparison.loc[comparison.index.intersection(key_metrics)])
    Your Turn — Run the Full Pipeline ⏱ 5 min

    Run full_ratio_analysis("ASIANPAINT.NS") (or your own company). Examine the four ratio DataFrames and answer:

    1. Is the company liquid? (current ratio)
    2. Is it solvent? (D/E, interest coverage)
    3. Is it profitable? (margins, ROE)
    4. Is it efficient? (CCC — is it negative?)

    Now run a second company from a DIFFERENT sector (e.g., a bank or steel company). Compare: which ratios look fundamentally different, and why?

    🔍 Debug Challenge — Divide by Zero ⏱ 3 min

    This function crashes for some companies. Find the bug:

    def compute_interest_coverage(income_stmt):
        ebit = income_stmt.loc['Operating Income']
        interest = income_stmt.loc['Interest Expense']
        return ebit / interest   # crashes for debt-free companies!

    With your partner: (1) When does this crash? (2) How would you handle it? (3) What should the ICR be for a company with no debt?

    Hint

    Interest of 0 → division by zero. Use interest.replace(0, np.nan) or set ICR to infinity/NaN for debt-free companies — a company with no interest has no coverage problem.

    X Excel Path — Your Ratio Pipeline Is the Summary Sheet + One Chart Excel

    The Python full_ratio_analysis() + compare_ratios() combination becomes a Ratios block on your Summary sheet (extend the one from Session 3):

    1. Columns = companies (B1: TCS, C1: INFY, D1: WIPRO…), plus two extra columns: Peer Median and Peer Max/Min.
    2. Rows = the ratios you built on the company sheets (Current Ratio, D/E, ICR, Net Margin, ROE, DuPont trio, CCC).
    3. Pull each value cross-sheet, e.g. Summary!B5 = =TCS!G34 (TCS's latest ICR).
    4. Add the peer statistics that make outliers visible:
    ' Peer Median in column F, dragged down all ratio rows:
    =MEDIAN(B5:D5)
    ' Best / Worst:
    =MAX(B5:D5) =MIN(B5:D5)
    ' Flag outliers vs the median (the Excel outlier detector):
    =IF(ABS(B5-$F5) > 0.5*ABS($F5), "OUTLIER", "")

    The project's two charts in Excel:

    • ROE vs D/E scatter: on Summary, select the ROE row + D/E row (Ctrl-click) → Insert → Scatter → add data labels → label from row 1 company names. This is the exact Python chart, built by selection.
    • Margin comparison bars: select the Net Margin / Op Margin rows → Insert → Clustered Column. Done.

    4.7 Interpreting Ratios: The Art Behind the Numbers

    Computing ratios is mechanical. Interpreting them requires judgment. Here is a framework for extracting insight from the numbers:

    4.7.1 The Three-Lens Test

    For every ratio, apply three lenses before drawing a conclusion:

  • Time-series lens: How has this ratio changed over the past 3–5 years? Is the trend improving, deteriorating, or stable? A single year's ratio is a snapshot; the trend is the movie.
  • Cross-sectional lens: How does this company's ratio compare to its direct peers? A 15% operating margin is outstanding for a commodity steel producer but mediocre for an IT services company.
  • Absolute benchmark lens: Is the ratio at a level that signals fundamental strength or weakness, regardless of industry? An interest coverage ratio below 1.5 is dangerous in any industry.
  • 4.7.2 Ratio Interaction Patterns

    Ratios do not exist in isolation. Certain combinations of ratios tell a coherent story:

    PatternRatios ObservedStory
    Quality Franchise High & stable gross margin + High ROE + Low D/E + Negative CCC The company has pricing power, earns excellent returns without leverage, and is financed by suppliers. Example: Titan, Asian Paints, Nestle India.
    Efficient Operator Moderate margins + High Asset Turnover + High ROE The company competes on operational efficiency, not pricing power. Example: DMart, Indigo.
    Leveraged Growth High ROE + High D/E + Low Interest Coverage Returns are juiced by debt. Sustainable only if growth continues and interest rates stay low. Example: Telecom, infrastructure.
    Melting Ice Cube Declining gross margins + Rising DSO + Rising DIO The company is losing pricing power, struggling to collect from customers, and building unsold inventory. Earnings quality is deteriorating. Investigate immediately.
    Accounting Manipulation Risk Widening gap between Net Income growth and Operating Cash Flow growth + Rapidly rising DSO + Falling Asset Turnover Profits may be fictional. Revenue might be recognized before cash is collected. Common in Indian real estate and infrastructure companies historically.
    💡
    Pro Tip: When you find an unusual ratio, always trace it back to the underlying financial statement line items. A sudden jump in ROE might be a genuine improvement in profitability — or it might be a debt-funded buyback that reduced equity. The ratio tells you what happened; the statements tell you why.
    🎨 Match the Pattern ⏱ 3 min

    Match each company description to a ratio interaction pattern from the table above:

    1. "Stable 45% gross margin, high ROE with zero debt, pays suppliers after collecting from customers." → ___
    2. "Profits keep rising, but operating cash flow is shrinking and receivables are exploding." → ___
    3. "Margins fell 300bp this year, inventory is piling up, and customers are paying slower." → ___
    Check your answers

    1) Quality Franchise · 2) Accounting Manipulation Risk · 3) Melting Ice Cube. Patterns let you spot trouble from ratios alone — before reading the annual report.

    X Excel Path — The Three-Lens Test, Automated Excel

    Each of the three lenses has a direct Excel implementation on your Drivers sheet:

    LensExcel FeatureHow
    Time-seriesSparklinesSelect a 5-year ratio row → Insert → Sparklines → Line, place in the row label cell. Every ratio gets a mini trend chart — deteriorating trends visibly flatten or fall.
    Cross-sectionalPeer Median columnAlready built in Section 4.6's Excel Path — add Conditional Formatting → Color Scales on the comparison rows: red (worst) to green (best) across companies, instantly.
    Absolute benchmarkThreshold rulesConditional Formatting rules: ICR < 1.5 red (Section 4.3), CCC < 0 green (Section 4.5), Current Ratio < 1 amber. These encode the red-flag tables of this chapter as automatic alarms.

    The "Melting Ice Cube" detector — one formula that fires when margins and days-ratios deteriorate together:

    ' Compares newest year G vs prior year F on a company sheet:
    =IF(AND(G36<F36, G43>F43, G44>F44),
       "⚠ MELTING ICE CUBE — margin down, DSO & DIO up", "OK")

    Copy this detector cell onto every company sheet — it replaces the eyeball test with an automatic alarm for the most dangerous pattern in the table above.

    📋 Stable content — Reviewed: June 2026

    4.8 Ratio Benchmarks for Key Indian Sectors

    Ratio benchmarks are context-dependent. Below are indicative ranges for major Indian sectors based on FY2024–25 data. These are starting points for analysis, not rigid targets — every company's business model within a sector can produce different ratio profiles.

    SectorCurrent RatioD/EOp Margin (%)ROE (%)Asset Turnover
    IT Services (TCS, Infosys, HCL, Wipro)2.5–4.50.0–0.222–2825–451.0–1.8
    Private Banks (HDFC Bank, ICICI, Kotak, Axis)N/A*N/A*N/A*12–18N/A*
    Consumer Staples (HUL, Nestle, Britannia)1.2–2.00.0–0.318–2525–601.2–2.5
    Consumer Discretionary (Titan, Asian Paints)2.0–3.50.1–0.515–2220–401.5–2.5
    Automotive (Maruti, Tata Motors, M&M)0.8–1.50.3–1.58–158–200.8–1.5
    Pharma (Sun Pharma, Dr. Reddy's, Cipla)1.5–3.00.1–0.615–2512–220.6–1.2
    Cement (UltraTech, Shree Cement, ACC)0.8–1.50.3–0.815–2210–180.4–0.8
    Telecom (Bharti Airtel, Reliance Jio)0.5–1.21.0–3.025–405–150.3–0.6
    Power / Utilities (NTPC, Power Grid)0.8–1.31.5–3.525–3510–160.2–0.5
    Metals & Mining (Tata Steel, Hindalco, JSW)0.8–1.50.8–2.010–205–200.4–0.8

    * Banks and financial institutions use a different ratio framework — capital adequacy, NIM, NPA ratios, and CASA ratio — which we address separately in later chapters.

    📝
    Note: These benchmarks are updated periodically. The latest data can always be obtained by running the compare_ratios() function from Section 4.6 against a current peer set. The Python pipeline you built is the ultimate source of up-to-date benchmarks.
    🔎 Sector Scavenger Hunt ⏱ 3 min

    Without looking at the table, identify the sector for each ratio profile:

    1. Current Ratio 3.0, D/E 0.1, ROE 35% → ___
    2. Current Ratio 1.0, D/E 2.0, Op Margin 30% → ___
    3. Current Ratio 0.9, D/E 0.5, Asset Turnover 0.6 → ___
    4. Asset Turnover 0.35, D/E 2.5, ROE 12% → ___

    Pair: Compare answers. Which single ratio was the strongest clue in each case?

    Check your answers

    1) IT Services · 2) Telecom · 3) Cement/Steel · 4) Power/Utilities. Clues: 1) high ROE+low D/E · 2) high debt+high margin · 3) low turnover+moderate debt · 4) very low turnover+high debt.

    Hands-On Project: Sector Ratio Diagnostic Report

    You are an equity research analyst covering one of the following Indian sectors: IT Services, Consumer Staples, or Pharmaceuticals. Your task is to produce a ratio diagnostic report comparing the top 4–5 companies in your chosen sector and identifying the strongest and weakest operators based on the numbers.

    Excel Option Complete the identical project in Excel: extend your Session 3 workbook with the ratio rows from this session's Excel Path boxes (liquidity, solvency, DuPont, CCC), roll all companies into the Summary sheet with Peer Median columns, apply the conditional-formatting traffic lights (ICR red < 1, CCC green < 0), and build the same three charts by selection (margin bars, ROE-vs-D/E scatter, CCC bars). Your deliverable is the workbook; the analysis, outlier identification, and 300-word report are identical requirements. Validation shortcut: your computed OPM, ROE, and D/E should match Screener.in's printed ratios — if they do, your formulas are correct.

    Steps

    1. Choose your sector and identify 4–5 listed companies using the .NS suffix. (Excel track: one worksheet per company, data pasted from Screener.in.)
    2. Run the compare_ratios() function from Section 4.6 for your chosen tickers. (Excel track: build the ratio rows + Summary sheet per Section 4.6's Excel Path.)
    3. Create visualizations (minimum 3):
      • A grouped bar chart comparing Operating Margin, Net Margin, and ROE across companies
      • A scatter plot of ROE vs Debt-to-Equity (label each company) — this reveals whether high ROE is from operations or leverage
      • A bar chart of the Cash Conversion Cycle for each company — identify working capital leaders and laggards
    4. Identify outliers: For each ratio, identify the best and worst performer. Investigate: is the outlier a genuine competitive advantage/disadvantage, or a temporary distortion?
    5. Write a 300-word diagnostic report covering:
      • Which company has the strongest overall financial profile? Justify with specific ratios.
      • Which company has the weakest profile? Is it distressed or just differently positioned?
      • One ratio that surprised you and what it implies for valuation.
    6. Analyst Showcase (NEW): In groups of 4, each person presents their ROE vs D/E scatter plot and defends the strongest and weakest company choice in 2 minutes. The group selects the most convincing diagnosis — and the class hears the top 2.
    View Solution / Walkthrough

    Sector Diagnostic: Indian IT Services (Representative Output)

    import matplotlib.pyplot as plt
    import seaborn as sns
    
    it_tickers = ['TCS.NS', 'INFY.NS', 'WIPRO.NS', 'HCLTECH.NS', 'TECHM.NS']
    it_labels = ['TCS', 'Infosys', 'Wipro', 'HCL Tech', 'Tech Mahindra']
    
    it_comparison = compare_ratios(it_tickers, it_labels)
    
    # --- Chart 1: Profitability Bar Chart ---
    fig, axes = plt.subplots(1, 3, figsize=(18, 6))
    
    profit_metrics = ['Operating Margin (%)', 'Net Margin (%)', 'ROE (%)']
    profit_data = it_comparison.loc[it_comparison.index.intersection(profit_metrics)]
    profit_data.T.plot(kind='bar', ax=axes[0], color=['#6c8cff', '#00c9a7', '#f0a040'])
    axes[0].set_title('Profitability Comparison — IT Services')
    axes[0].set_ylabel('Percent (%)')
    axes[0].legend(fontsize=8)
    axes[0].tick_params(axis='x', rotation=30)
    
    # --- Chart 2: ROE vs Debt-to-Equity Scatter ---
    ax = axes[1]
    if 'ROE (%)' in it_comparison.index and 'Debt-to-Equity' in it_comparison.index:
        x = it_comparison.loc['Debt-to-Equity']
        y = it_comparison.loc['ROE (%)']
        ax.scatter(x, y, s=200, c='#6c8cff', edgecolors='white', linewidth=2, zorder=5)
        for i, name in enumerate(it_comparison.columns):
            ax.annotate(name, (x.iloc[i], y.iloc[i]),
                        textcoords="offset points", xytext=(8, 5), fontsize=9)
        ax.set_xlabel('Debt-to-Equity')
        ax.set_ylabel('ROE (%)')
        ax.set_title('ROE vs Leverage — Does Debt Drive Returns?')
        ax.axhline(y=it_comparison.loc['ROE (%)'].mean(), color='gray',
                   linestyle='--', alpha=0.5, label='Average ROE')
        ax.legend(fontsize=8)
    
    # --- Chart 3: Cash Conversion Cycle ---
    ax = axes[2]
    ccc_data = it_comparison.loc[it_comparison.index.intersection(['Cash Conversion Cycle'])]
    if not ccc_data.empty:
        colors = ['#00c9a7' if v < 0 else '#f0a040' if v < 30 else '#e0556a'
                  for v in ccc_data.iloc[0]]
        ax.bar(ccc_data.columns, ccc_data.iloc[0], color=colors)
        ax.set_title('Cash Conversion Cycle (Days)')
        ax.set_ylabel('Days')
        ax.axhline(y=0, color='green', linestyle='--', alpha=0.5, label='CCC = 0')
        ax.legend(fontsize=8)
        ax.tick_params(axis='x', rotation=30)
    
    plt.suptitle('Indian IT Services — Ratio Diagnostic Report',
                 fontsize=14, fontweight='bold', y=1.02)
    plt.tight_layout()
    plt.show()

    Sample Diagnostic Report (300 words):

    TCS demonstrates the strongest overall financial profile among Indian IT services companies. Its operating margin (~26%) leads the peer group, reflecting superior execution, scale advantages, and a higher proportion of high-value digital transformation engagements. Combined with negligible debt (D/E < 0.05), TCS's 45%+ ROE is almost entirely operationally driven, not levered — the highest-quality return profile possible. The negative cash conversion cycle signals that TCS collects from customers before paying its own obligations, effectively running on negative working capital.

    Tech Mahindra shows the weakest profitability profile with an operating margin of ~12%, roughly half of TCS's. This is partly structural — Tech Mahindra has higher exposure to lower-margin telecom verticals and communication services. However, the gap also reflects operational efficiency differences. Its ROE of ~15% is respectable but, combined with slightly higher leverage, suggests a less durable return profile.

    The most surprising finding is the working capital divergence. While TCS and Infosys maintain tight receivable management (DSO ~60 days), Tech Mahindra's DSO exceeds 90 days — implying either looser client payment terms or slower collection efforts. For a DCF valuation, this translates to higher working capital investment for every rupee of revenue growth, directly reducing free cash flow. An analyst forecasting identical revenue growth for TCS and Tech Mahindra would miss a critical difference in cash generation. This is exactly why ratio analysis must precede forecasting.

    Key Takeaways

    1

    Four ratio families, four questions: Liquidity = survival, Solvency = sustainability, Profitability = earnings power, Efficiency = management quality. All four must be assessed before you value a company.

    2

    The DuPont decomposition reveals whether high ROE comes from operational excellence (high margins, high turnover) or financial engineering (high leverage). The former is sustainable; the latter is fragile.

    3

    The Cash Conversion Cycle directly impacts free cash flow. Two companies with identical margins can have materially different valuations if one ties up far more capital in working capital.

    4

    Python automation turns hours of manual ratio computation into seconds. The pipeline from Section 4.6 is the foundation you will reuse for every company you value in this course.

    5

    Ratios are diagnostic tools, not answers. A ratio tells you what to investigate, not why. Always trace anomalies back to the underlying financial statement line items.

    Test Your Understanding

    1. A company has a Current Ratio of 1.2 and a Quick Ratio of 0.4. What does the large gap between these two ratios most likely indicate?

    2. The DuPont decomposition expresses ROE as the product of three drivers. Which of the following is the correct formula?

    3. Which of the following patterns in financial ratios would raise the strongest concern about potential accounting manipulation?

    4. A company has an Interest Coverage Ratio of 0.8. What does this mean?

    5. Why is a negative Cash Conversion Cycle (CCC) considered desirable for a business?

    📝 Quick Reflection ⏱ 1 min

    Which ratio family do you now understand best — and which still feels fuzzy? Write one sentence for each. In Session 5 we build on ROIC, and you will use these ratios to judge which companies actually create value.