English | 中文
A Claude/agent skill + standalone Python tool that parses Futu (富途證券) Hong Kong
statements — the annual statement (年度账单 .xlsx) or the monthly e-statements
(證券月結單 .pdf) — into tax-ready CSVs, for individual income tax on foreign income
(个税 境外所得), CRS reporting, and broker P&L reconciliation.
It reads official statement files only — it does not use the Futu OpenD / API (which exposes no realized P&L, no fees, and unlabeled dividends).
Futu's HK statements are authoritative for tax, but:
- there is no realized-P&L section — it must be reconstructed from the trade list;
- there is no "dividend" section — cash dividends hide inside
公司行動(corporate actions); - interest, deposits and withdrawals are mixed together inside
資金進出.
This repo captures the method (see SKILL.md) and ships a parser that does it.
| Input | Where to get it | Notes |
|---|---|---|
年度账单 .xlsx (preferred) |
Futu app → 我的 → 賬戶詳情 → 年度账单 | Cleaner; has 期初/期末 holdings, so cross-year positions realize correctly |
月結單 .pdf (one or many) |
Futu app → 我的 → 賬戶詳情 → 電子結單/月結單 | Needs pdftotext; no opening positions |
Both are exported from the Futu mobile app — there's no API/CLI to auto-fetch, so this
tool parses the files you provide rather than downloading them. Help: how to get the monthly
statement → https://www.futuhk.com/support/topic2_332 (the annual statement is in the same
app). If no .xlsx/.pdf is found at runtime, the tool prints these steps.
Point the tool at a file or a folder. If a folder has both, the xlsx wins — it's more
accurate: the monthly PDFs only cover the calendar year, so a position opened last December
and closed in January is invisible, whereas the annual xlsx seeds it from 期初 (opening)
holdings. (In one real case the two methods differed by exactly one year-boundary option's premium.)
pip install openpyxl # for the annual .xlsx
brew install poppler # for the monthly .pdf (or: apt install poppler-utils) → pdftotextInstall only what your input needs. Tested on Python 3.10+.
python3 parse_futu_statement.py 2025_年度账单.xlsx -o out/ --rate 0.90322 # annual xlsx
python3 parse_futu_statement.py /folder-of-pdfs -o out/ --rate 0.90322 # monthly PDFs
python3 parse_futu_statement.py /folder -o out/ --rate 0.90322 # both -> xlsx winsStatements are handled per currency (HKD, USD, …): realized P&L, dividends and tax are
grouped by currency and never summed across them. --rate is the HKD→RMB year-end mid-rate
(中间价) shorthand; for other currencies pass --fx-rate CCY=RATE (repeatable), e.g.
--fx-rate HKD=0.90322 --fx-rate USD=7.0288. When neither is given, built-in year-end rates
are used if available for the detected year. The year is auto-detected.
| File | Contents |
|---|---|
futu_<YEAR>_成交明细.csv |
stock/option trades; 变动金额 is already net of fees |
futu_<YEAR>_股息利息现金流.csv |
dividends (公司行动), interest, deposits/withdrawals, fees |
futu_<YEAR>_期权行权到期.csv |
option expiry (EXP) / assignment (ASS) events |
futu_<YEAR>_已实现盈亏_按标的.csv |
realized P&L per instrument (average-cost) |
futu_<YEAR>_账户净值.csv |
opening / closing balances (cross-check) |
futu_<YEAR>_税务汇总.csv |
tax summary — capital gains / dividends / interest + tax due (needs --rate) |
The script prints Σ变动金额, total dividends, and realized P&L so you can sanity-check.
Average-cost per instrument, using Futu's explicit 開倉/平倉 (open/close) labels (buy vs
sell from the sign of 变动金额, so it also handles 强平 forced-liquidation rows). Options
that expired or were assigned are closed at zero (premium fully realized); positions still
held at year-end keep realized = 0 (their gain is unrealized and not taxable for the year).
With the annual xlsx, 期初 holdings seed carried-in positions so cross-year items are
captured. Cross-check against ΔNAV − net deposits. Details in SKILL.md.
Drop this folder into your skills directory (e.g. ~/.claude/skills/parsing-futu-statements/)
or install via your plugin manager. Claude loads SKILL.md when you ask it to
parse Futu statements or compute Futu P&L / dividends for tax.
This repo contains no personal data. The parser reads whatever file you point it at and
writes CSVs locally. .gitignore blocks *.pdf, *.xlsx and *.csv so you can't accidentally
commit statements or results.
Validated against a full year via both inputs: the monthly PDFs and the annual xlsx reconcile exactly on every trade, dividend, interest and per-instrument figure — and the xlsx additionally catches a cross-year option the monthly-only view misses. Trade numbers and codes are exact; option names are decoded from the contract code, stock names harvested from the holdings data.
MIT