---
name: kenneth-french-data-library-ingestion
description: "How to get Kenneth French Data Library data into a pandas DataFrame and Parquet: access, the request, the format, limits, quirks and terms."
---

# Load Kenneth French US factors into pandas and Parquet

Source entry: https://signal-lab-jet.vercel.app/datasets/kenneth-french-data-library
Provider: https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html
Checked against the provider's documentation: 2026-10-29

## Access
- No account or API key. Download the ZIP file directly.
- No reuse license is stated; the library carries a copyright notice.

## Request
```bash
curl -O https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/F-F_Research_Data_Factors_CSV.zip
```

## Format
ZIP containing one CSV text file. It has prose, a monthly table, a blank line, then an annual table; factor returns are percentages.

## Load into pandas and Parquet
Needs Python 3 with requests, pandas and pyarrow.
```python
"""Kenneth French US three factors (monthly) -> pandas -> Parquet. No key."""
import io
import zipfile
import requests
import pandas as pd

URL = "https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/F-F_Research_Data_Factors_CSV.zip"
r = requests.get(URL, timeout=60)
r.raise_for_status()
with zipfile.ZipFile(io.BytesIO(r.content)) as archive:
    text = archive.read(archive.namelist()[0]).decode("utf-8")
lines = text.splitlines()
header = next(i for i, line in enumerate(lines) if line.startswith(",Mkt-RF"))
end = next(i for i in range(header + 1, len(lines)) if not lines[i].strip())
df = pd.read_csv(io.StringIO("\n".join(lines[header:end])))
df = df.rename(columns={df.columns[0]: "month", "Mkt-RF": "mkt_rf"})
df["month"] = pd.to_datetime(df["month"].astype(str), format="%Y%m")
for column in ("mkt_rf", "SMB", "HML", "RF"):
    df[column] = pd.to_numeric(df[column]) / 100
df.to_parquet("kenneth_french_us_3_factors_monthly.parquet", index=False)
print(f"{len(df):,}", "monthly rows,", df["month"].min().date(), "to", df["month"].max().date())
```
Run by us on 2026-10-29 (python 3.13.5 | pandas 3.1.0 | pyarrow 26.0.0 | requests 2.34.2). Result: 1,203 monthly rows, 1926-07-01 to 2026-09-01.

## Limits
- Rate limit: Not stated.

## Quirks
- The file is not a single ordinary CSV table; isolate the monthly block before parsing.
- From the January 2025 release, US returns use CRSP CIZ files and monthly returns compound daily returns with dividends reinvested on ex-dates.
- The full history is reconstructed each month and can change.
- Divide factor values by 100 before treating them as decimal returns.

## Terms and attribution
- No reuse license is stated. The page says Copyright Eugene F. Fama and Kenneth R. French.
- Confirm permission for redistribution or commercial reuse before publishing a copy.
- Terms page: https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html

## Sources
- https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html: "Copyright Eugene F. Fama and Kenneth R. French"
- https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html: "We reconstruct the full history of returns each month when we update the portfolios."
- https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html: "monthly returns are compounded daily returns with dividends reinvested on their ex-dates"

Information for educational purposes only. Free tiers, limits and licenses belong to the providers and may change; check the provider's own terms before using the data.
