fintech-algorithms
Using a coding agent? Give it the skill: npx skills add IslamBaraka90/Fintech-Algorithms-Library What it does →

Common-Size Statements

Install and import#

bash
npm install fintech-algorithms
ts
import { commonSizeStatements } from "fintech-algorithms/fundamental-analysis-and-valuation/statement-ratios/common-size-statements";

Signature#

commonSizeStatements(input)

Divides every line item of each period by that period's own base line to give common-size percentages, and tracks one focus line's percentage and its change in percentage points against the previous period.

Parameters#

NameTypeNotes
input{ statement_type: string; base_label: string; focus_label: string; periods: { period: string; items: { label: string; value: number }[] }[] }A plain object. statement_type must be income or balance and governs whether a negative base is allowed. base_label names the row every value is divided by and focus_label names the row that is tracked across periods; both must exist in every period. periods is an array of at least two objects, each with a nonempty period string and an items array of at least four rows carrying a unique nonempty label and a finite value, in the same order in every period.

Returns#

{ statement_type: string; base_label: string; focus_label: string; period_count: number; line_item_count: number; focus_percentage: number; focus_change_pp: number; periods: { period: string; base_value: number; focus_percentage: number; focus_change_pp: number | null; items: { label: string; value: number; common_size_pct: number }[] }[]; state: string; reason: string }

statement_type, base_label and focus_label echo the inputs, and period_count and line_item_count report how many periods and rows per period were normalized. periods carries one entry per input period with its trimmed period name, the base_value used as the divisor, the focus row's focus_percentage, the focus_change_pp against the previous period (null for the first), and items repeating each label and value alongside its common_size_pct. The top-level focus_percentage and focus_change_pp are the last period's. state is always calculated and reason is signed-line-items-divided-by-period-base.

Errors#

  • When statement_type is neither income nor balance — throws RangeError
  • When base_label or focus_label is not a nonempty string — throws RangeError
  • When periods is not an array of at least two entries, an entry is not an object, its period is not a nonempty string, or its items array holds fewer than four rows — throws RangeError
  • When an item is not an object, its label is empty or repeats within the period, or its value is not a finite number — throws RangeError
  • When two periods do not use the same ordered labels, or a period is missing base_label or focus_label — throws RangeError
  • When the base value is zero, or negative when statement_type is balance — throws RangeError

Complexity: time O(n), space O(n).

Worked example#

verified This is the worked example published in the article, replayed by the test suite on every run. The output cannot drift.

Input#

input
{
  "statement_type": "income",
  "base_label": "Revenue",
  "focus_label": "Net income",
  "periods": [
    {
      "period": "FY2023",
      "items": [
        {
          "label": "Revenue",
          "value": 1200
        },
        {
          "label": "Cost of goods sold",
          "value": -720
        },
        {
          "label": "Gross profit",
          "value": 480
        }
      ]
    },
    {
      "period": "FY2024",
      "items": [
        {
          "label": "Revenue",
          "value": 1320
        },
        {
          "label": "Cost of goods sold",
          "value": -805
        },
        {
          "label": "Gross profit",
          "value": 515
        }
      ]
    },
    {
      "period": "FY2025",
      "items": [
        {
          "label": "Revenue",
          "value": 1450
        },
        {
          "label": "Cost of goods sold",
          "value": -899
        },
        {
          "label": "Gross profit",
          "value": 551
        }
      ]
    }
  ]
}

Call#

commonSizeStatements(input)

Returns#

object with 10 fields: statement_type, base_label, focus_label, period_count, line_item_count, focus_percentage, focus_change_pp, periods, …

{
  "statement_type": "income",
  "base_label": "Revenue",
  "focus_label": "Net income",
  "period_count": 4,
  "line_item_count": 12,
  "focus_percentage": 8.8125,
  "focus_change_pp": 0.674568965517,
  "periods": [
    {
      "period": "FY2023",
      "base_value": 1200,
      "focus_percentage": 9.416666666667,
      "focus_change_pp": null,
      "items": [
        {
          "label": "Revenue",
          "value": 1200,
          "common_size_pct": 100
        },
        {
          "label": "Cost of goods sold",
          "value": -720,
          "common_size_pct": -60
        },
        {
          "label": "Gross profit",
          "value": 480,
          "common_size_pct": 40
        }
      ]
    },
    {
      "period": "FY2024",
      "base_value": 1320,
      "focus_percentage": 8.787878787879,
      "focus_change_pp": -0.628787878788,
      "items": [
        {
          "label": "Revenue",
          "value": 1320,
          "common_size_pct": 100
        },
        {
          "label": "Cost of goods sold",
          "value": -805,
          "common_size_pct": -60.984848484848
        },
        {
          "label": "Gross profit",
          "value": 515,
          "common_size_pct": 39.015151515152
        }
      ]
    },
    {
      "period": "FY2025",
      "base_value": 1450,
      "focus_percentage": 8.137931034483,
      "focus_change_pp": -0.649947753396,
      "items": [
        {
          "label": "Revenue",
          "value": 1450,
          "common_size_pct": 100
        },
        {
          "label": "Cost of goods sold",
          "value": -899,
          "common_size_pct": -62
        },
        {
          "label": "Gross profit",
          "value": 551,
          "common_size_pct": 38
        }
      ]
    }
  ],
  "state": "calculated",
  "reason": "signed-line-items-divided-by-period-base"
}

Other exports#

This module also exports dupontDecomposition, roicCalculation, cashConversionCycle, interestCoverageRatio, netDebtToEbitda, calculate. Every module additionally exports run as an alias of its primary function, and a meta object carrying its catalog id, domain, family, shape and article URL.

Diagrams#

Common-Size Statements — article hero
Common-Size Statements — definition comparison
Common-Size Statements — evidence lineage
Common-Size Statements — formula anatomy
Common-Size Statements — system map
Common-Size Statements — worked example

How it works#

This page states the contract — how to call it correctly. The article explains the concept: why it works, and where it breaks.

Read the article →

References#

The rest of the Statement Ratios family#