---
name: xlsx
description: Create, read, edit, and analyze Excel (.xlsx) workbooks — write DataFrames to sheets with formatting/number formats/conditional formatting/charts, read sheets back into pandas, and append to existing workbooks. Use when the task involves producing or parsing .xlsx files, exporting tabular results (IC/IR tables, factor returns, backtest summaries, holdings), or building multi-sheet Excel reports.
---

# Excel (.xlsx) skill

Toolkit for working with Excel workbooks in Python. Two engines are available and both are installed:

- **openpyxl** (3.1.5) — read AND write; full styling, conditional formatting, native charts, formulas. Use this when you need to *read* existing files or *edit in place*.
- **xlsxwriter** (3.2.9) — write-only but richer/faster charting & formatting. Used by pandas' `to_excel(engine="xlsxwriter")`.

Default to **openpyxl** unless you specifically need xlsxwriter's charts. Never guess the API — the helper scripts in `scripts/` cover the common cases; read the one you need and call it, or adapt its code.

## Quick decision guide

| Task | Approach |
|------|----------|
| Dump one or more DataFrames to a styled workbook | `scripts/df_to_xlsx.py` |
| Read a workbook back into pandas (all sheets) | `scripts/read_xlsx.py` |
| Append a sheet to / edit an existing workbook | open with `openpyxl.load_workbook(path)`, modify, `.save()` |
| Add a chart from a data range | see "Charts" below or `scripts/df_to_xlsx.py --chart` |
| Quant report (multi-sheet: summary + per-factor) | call `df_to_xlsx.py` once per sheet with `--append`, or use the multi-sheet snippet below |

## Helper scripts

All scripts use the project Python (`/intern9/huhongkai/miniconda3/bin/python`). Run with `python scripts/<name>.py --help` first if unsure.

- **`scripts/df_to_xlsx.py`** — Write a CSV/Parquet (or stdin) into a styled .xlsx sheet: bold frozen header, auto column widths, number formats, optional conditional color scale, optional line/column chart. Supports `--append` to add a sheet to an existing file.
- **`scripts/read_xlsx.py`** — Load every sheet of a workbook into pandas and print shape + head, or dump a chosen sheet to CSV/Parquet.

## Multi-sheet report (the common quant case)

```python
import pandas as pd
with pd.ExcelWriter("report.xlsx", engine="openpyxl") as xw:
    summary_df.to_excel(xw, sheet_name="Summary", index=False)
    ic_df.to_excel(xw, sheet_name="IC_by_factor", index=True)
    backtest_df.to_excel(xw, sheet_name="Backtest", index=True)
# then re-open with openpyxl to style headers / add number formats / charts
```

## Styling cheatsheet (openpyxl)

```python
from openpyxl import load_workbook
from openpyxl.styles import Font, PatternFill, Alignment
from openpyxl.formatting.rule import ColorScaleRule
from openpyxl.utils import get_column_letter

wb = load_workbook("report.xlsx"); ws = wb["Summary"]
# bold header + freeze
for c in ws[1]:
    c.font = Font(bold=True); c.fill = PatternFill("solid", fgColor="DDEBF7")
ws.freeze_panes = "A2"
# percentage number format on a column (e.g. returns)
for row in ws.iter_rows(min_row=2, min_col=2, max_col=2):
    for cell in row: cell.number_format = "0.00%"
# 4-decimal for IC values
# conditional color scale (red-white-green) over a range
ws.conditional_formatting.add("B2:B100",
    ColorScaleRule(start_type="min", start_color="F8696B",
                   mid_type="num", mid_value=0, mid_color="FFFFFF",
                   end_type="max", end_color="63BE7B"))
wb.save("report.xlsx")
```

## Native chart (openpyxl)

```python
from openpyxl.chart import LineChart, Reference
ch = LineChart(); ch.title = "Cumulative factor return"
data = Reference(ws, min_col=2, min_row=1, max_row=ws.max_row)   # incl. header for legend
cats = Reference(ws, min_col=1, min_row=2, max_row=ws.max_row)
ch.add_data(data, titles_from_data=True); ch.set_categories(cats)
ws.add_chart(ch, "E2"); wb.save("report.xlsx")
```

## Number-format reference

| Use | format string |
|-----|---------------|
| Return / pct | `"0.00%"` |
| IC / IR (4dp) | `"0.0000"` |
| Price (2dp) | `"#,##0.00"` |
| Large counts | `"#,##0"` |
| Date | `"yyyy-mm-dd"` |

## Gotchas

- `.xls` (old format) is NOT supported by these engines — convert to `.xlsx` first.
- openpyxl does NOT evaluate formulas; it stores the formula string. To read a computed value, the file must have been saved by Excel/LibreOffice (cached value), and you must `load_workbook(path, data_only=True)`.
- When `to_excel` writes a MultiIndex, set `merge_cells=False` if you plan to re-read programmatically.
- Always close/`save()` before re-reading; pandas `ExcelWriter` must exit its `with` block first.
