Skip to content
This repository was archived by the owner on Apr 8, 2026. It is now read-only.

Commit 4299780

Browse files
Merge pull request #3 from timothyhartzog/copilot/gap-analysis-healthcare-finance
Build out healthcare finance modeling toolkit from gap analysis
2 parents 903009e + 2748bd8 commit 4299780

35 files changed

Lines changed: 3876 additions & 14 deletions

.github/workflows/ci.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: ["main", "master", "copilot/**"]
6+
pull_request:
7+
branches: ["main", "master"]
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
test:
14+
name: Julia ${{ matrix.julia-version }} — ${{ matrix.os }}
15+
runs-on: ${{ matrix.os }}
16+
strategy:
17+
fail-fast: false
18+
matrix:
19+
julia-version: ["1.10", "1.11"]
20+
os: [ubuntu-latest]
21+
22+
steps:
23+
- uses: actions/checkout@v4
24+
25+
- name: Set up Julia ${{ matrix.julia-version }}
26+
uses: julia-actions/setup-julia@v2
27+
with:
28+
version: ${{ matrix.julia-version }}
29+
30+
- name: Cache Julia packages
31+
uses: julia-actions/cache@v2
32+
33+
- name: Install dependencies
34+
uses: julia-actions/julia-buildpkg@v1
35+
36+
- name: Run tests
37+
uses: julia-actions/julia-runtest@v1
38+
39+
- name: Upload coverage (Codecov)
40+
if: matrix.julia-version == '1.10' && matrix.os == 'ubuntu-latest'
41+
uses: codecov/codecov-action@v4
42+
with:
43+
file: lcov.info
44+
fail_ci_if_error: false

Project.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
name = "HealthcareFinance"
22
uuid = "6f7d9b44-0d76-4ac4-9b12-8e3f2f5a1001"
33
authors = ["Timothy Hartzog"]
4-
version = "0.1.0"
4+
version = "0.2.0"
55

66
[deps]
77
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
88
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
99
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
1010
GLM = "38e38edf-8417-5370-95a0-9cbb8c7f171a"
1111
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
12+
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
13+
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
1214
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
1315

1416
[compat]
@@ -18,3 +20,4 @@ Distributions = "0.25"
1820
GLM = "1"
1921
JuMP = "1"
2022
julia = "1.10"
23+
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# Chapter 4: Financial Analysis for Healthcare Organizations
2+
3+
## Learning Objectives
4+
After completing this chapter, students will be able to:
5+
1. Construct and interpret hospital income statements using HFMA conventions
6+
2. Compute and benchmark key financial ratios for health systems
7+
3. Apply DuPont analysis to decompose return on equity (net assets)
8+
4. Evaluate financial performance using bond-rating agency frameworks
9+
10+
---
11+
12+
## 4.1 Healthcare Financial Statements
13+
14+
Hospital financial statements differ from those of for-profit corporations in
15+
important ways:
16+
17+
- **Revenue deductions** (contractual adjustments, charity care, bad debt) are
18+
netted against gross charges to arrive at *net patient revenue*
19+
- **Non-profit status** means equity is replaced by *net assets* (unrestricted,
20+
temporarily restricted, permanently restricted) per FASB ASC 958
21+
- **Community benefit** reporting is required on IRS Form 990, Schedule H
22+
23+
### Net Patient Revenue Waterfall
24+
25+
```
26+
Gross Charges
27+
− Contractual Adjustments (negotiated write-offs to payers)
28+
− Charity Care (free care at cost to qualifying patients)
29+
− Bad Debt (uncollectible after good-faith billing)
30+
= Net Patient Revenue
31+
+ Other Operating Revenue (grants, cafeteria, parking, etc.)
32+
= Total Operating Revenue
33+
− Operating Expenses
34+
= Operating Income (Excess of Revenue over Expenses)
35+
```
36+
37+
### Julia Example
38+
39+
```julia
40+
using HealthcareFinance
41+
42+
stmt = income_statement(
43+
50_000_000.0, # gross charges
44+
18_000_000.0, # contractual adjustments
45+
500_000.0, # bad debt
46+
1_000_000.0, # charity care
47+
27_000_000.0; # operating expenses
48+
other_income = 500_000.0
49+
)
50+
51+
println("Net patient revenue: \$", stmt.net_patient_revenue)
52+
println("Operating margin: ", round(stmt.total_margin * 100, digits=2), "%")
53+
```
54+
55+
---
56+
57+
## 4.2 Key Financial Ratios
58+
59+
### Profitability
60+
| Ratio | Formula | Typical Benchmark |
61+
|---|---|---|
62+
| Operating margin | Operating income / Total operating revenue | 2–4% |
63+
| Total margin | Excess revenue / Total revenue | 3–5% |
64+
| EBITDA margin | EBITDA / Total operating revenue | 8–12% |
65+
| Return on assets | Net income / Total assets | 2–4% |
66+
67+
### Liquidity
68+
| Ratio | Formula | Typical Benchmark |
69+
|---|---|---|
70+
| Current ratio | Current assets / Current liabilities | ≥ 2.0 |
71+
| Days cash on hand | Cash / (Operating expenses / 365) | ≥ 150 days |
72+
| Days in AR | AR balance / (Net revenue / 365) | ≤ 50 days |
73+
74+
### Leverage (Credit)
75+
| Ratio | Formula | Moody's A Benchmark |
76+
|---|---|---|
77+
| Debt-to-capitalization | LTD / (LTD + Net assets) | < 35% |
78+
| DSCR | (Income + D&A) / Debt service | ≥ 2.0× |
79+
| Maximum annual debt service | MADS / Operating revenue | < 3% |
80+
81+
### Julia Example: Balance Sheet Analysis
82+
83+
```julia
84+
ratios = balance_sheet_ratios(
85+
12_000_000.0, # current assets
86+
5_000_000.0, # current liabilities
87+
3_000_000.0, # cash
88+
80_000_000.0, # total assets
89+
45_000_000.0, # total liabilities
90+
35_000_000.0, # net assets
91+
30_000_000.0 # long-term debt
92+
)
93+
94+
println("Current ratio: ", round(ratios.current_ratio, digits=2))
95+
println("D/Cap ratio: ", round(ratios.long_term_debt_to_capitalization * 100, digits=1), "%")
96+
dscr = debt_service_coverage_ratio(2_000_000.0, 4_000_000.0, 2_500_000.0)
97+
println("DSCR: ", round(dscr, digits=2))
98+
```
99+
100+
---
101+
102+
## 4.3 DuPont Analysis for Healthcare
103+
104+
The DuPont framework decomposes return on net assets (RONA):
105+
106+
```
107+
RONA = Net Profit Margin × Asset Turnover × Equity Multiplier
108+
```
109+
110+
Where:
111+
- **Net profit margin** = Net income / Revenue
112+
- **Asset turnover** = Revenue / Total assets
113+
- **Equity multiplier** = Total assets / Net assets
114+
115+
---
116+
117+
## 4.4 Community Benefit and Non-Profit Accountability
118+
119+
Under IRS Schedule H, non-profit hospitals must quantify:
120+
1. Financial assistance (charity care at cost)
121+
2. Unreimbursed Medicaid
122+
3. Health professions education
123+
4. Community health improvement services
124+
5. Research
125+
126+
Industry average is 7–10% of total operating expense.
127+
128+
```julia
129+
cbr = charitable_community_benefit_rate(7_500_000.0, 100_000_000.0)
130+
println("Community benefit rate: ", round(cbr * 100, digits=1), "%")
131+
```
132+
133+
---
134+
135+
## Key Terms
136+
- **Contractual adjustment**: Write-off of the difference between billed charges and
137+
a payer's allowed amount per contract
138+
- **EBITDA**: Earnings before interest, taxes, depreciation, and amortization — key
139+
credit metric used by Moody's, S&P, and Fitch
140+
- **Days cash on hand**: Liquidity indicator; number of days operations could
141+
continue using only available cash and investments
142+
- **DSCR**: Debt service coverage ratio; measures ability to service debt obligations

book/chapters/05_budgeting.md

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# Chapter 5: Budgeting and Variance Analysis
2+
3+
## Learning Objectives
4+
1. Build an operating budget using fixed and variable cost structures
5+
2. Construct a flexible budget adjusted to actual volume
6+
3. Decompose total variance into volume, price, efficiency, and mix components
7+
4. Rank and select capital projects using NPV and strategic scoring
8+
5. Apply zero-based budgeting to healthcare service lines
9+
10+
---
11+
12+
## 5.1 The Operating Budget
13+
14+
Healthcare budgets integrate clinical activity (volume) with financial targets.
15+
16+
**Basic structure:**
17+
```
18+
Revenue = Price × Volume
19+
Variable Costs = Variable Cost Rate × Volume
20+
Contribution Margin = Revenue − Variable Costs
21+
Operating Income = Contribution Margin − Fixed Costs
22+
```
23+
24+
### Julia Example
25+
26+
```julia
27+
using HealthcareFinance
28+
29+
# Cardiology clinic: 8,000 visits budgeted at $150/visit
30+
bud = operating_budget(600_000.0, 45.0, 8_000, 150.0)
31+
println("Budgeted operating income: \$", bud.operating_income)
32+
println("Break-even volume: ", break_even_units(600_000.0, 150.0, 45.0), " visits")
33+
```
34+
35+
---
36+
37+
## 5.2 Flexible Budgeting
38+
39+
A *static budget* is prepared at the start of the period. A *flexible budget*
40+
adjusts the cost and revenue targets to the actual volume, isolating whether
41+
variance is from volume or other factors.
42+
43+
```julia
44+
# Actual volume was 8,800 (10% above budget)
45+
flex = flex_budget(600_000.0, 45.0, 8_800, 150.0)
46+
47+
# Variance analysis
48+
vol_var = volume_variance(150.0 - 45.0, 8_800, 8_000) # CM × ΔVolume
49+
price_var = price_variance(148.0, 150.0, 8_800) # actual price was $148
50+
51+
println("Volume variance (F/U): \$", vol_var)
52+
println("Price variance (F/U): \$", price_var)
53+
```
54+
55+
---
56+
57+
## 5.3 Four-Variance Decomposition
58+
59+
| Variance | Formula | Meaning |
60+
|---|---|---|
61+
| **Volume** | Budgeted CM/unit × (Actual − Budgeted volume) | More/fewer encounters |
62+
| **Price (Rate)** | (Actual price − Budget price) × Actual volume | Revenue per unit |
63+
| **Efficiency** | Budgeted cost × (Actual inputs − Standard inputs) | Resource productivity |
64+
| **Mix** | Shift in composition across service lines or payers | Patient/payer mix effect |
65+
66+
Favorable variances increase operating income; unfavorable reduce it.
67+
68+
---
69+
70+
## 5.4 Capital Budgeting
71+
72+
Capital projects in healthcare often require Certificate of Need (CON) approval
73+
and involve long useful lives (10–30 years for buildings, 5–10 for equipment).
74+
75+
**Decision criteria:**
76+
1. **NPV > 0**: creates economic value
77+
2. **IRR > WACC**: returns exceed cost of capital
78+
3. **DSCR ≥ 1.25**: can service associated debt
79+
80+
```julia
81+
cfs = [-2_000_000.0, 500_000.0, 600_000.0, 700_000.0, 800_000.0, 600_000.0]
82+
project_npv = npv(0.07, cfs)
83+
project_irr = irr(cfs)
84+
println("NPV: \$", round(project_npv))
85+
println("IRR: ", round(project_irr * 100, digits=2), "%")
86+
println("PI: ", profitability_index(project_npv, 2_000_000.0))
87+
```
88+
89+
### Capital Project Ranking
90+
91+
```julia
92+
projects = [
93+
(name="OR Renovation", npv=800_000.0, strategic_score=9.0),
94+
(name="MRI Replacement", npv=600_000.0, strategic_score=8.0),
95+
(name="Parking Structure", npv=200_000.0, strategic_score=4.0),
96+
(name="Telehealth Platform", npv=400_000.0, strategic_score=9.5),
97+
]
98+
ranked = capital_budget_rank(projects; npv_weight=0.6, strategic_weight=0.4)
99+
for (i, p) in enumerate(ranked)
100+
println("$i. $(p.name): score = $(round(p.composite_score, digits=2))")
101+
end
102+
```
103+
104+
---
105+
106+
## 5.5 Zero-Based Budgeting in Healthcare
107+
108+
ZBB requires each budget line item to be justified from scratch each period,
109+
rather than incrementing prior year. Useful for administrative overhead review.
110+
111+
```julia
112+
# Score a telehealth program for ZBB approval
113+
score = zero_based_budget_score(9.0, 8.5, 9.0;
114+
weights=(0.4, 0.3, 0.3))
115+
println("ZBB score (0–10): ", round(score, digits=2))
116+
```
117+
118+
---
119+
120+
## Key Terms
121+
- **Contribution margin**: Revenue minus variable costs; the amount available to cover fixed costs and generate profit
122+
- **Flexible budget**: A budget restated at actual volume to isolate non-volume variances
123+
- **Capital rationing**: Situation where available capital is insufficient to fund all positive-NPV projects
124+
- **Zero-based budgeting**: Budget methodology requiring justification of all expenditures from zero

0 commit comments

Comments
 (0)