第 1 章 · 02 安装与第一个组合 本节摘要:本节带你从零跑出第一个最优组合——把抽象的「四层架构」落到可执行代码上。先讲清安装方式:pip 一行命令,源码安装的备用方案,以及 Windows/macOS 上的 C++ 编译依赖。再讲清输入数据的规范——价格 DataFrame 的长宽格式、索引为日期、列为资产代码、值为复权收盘价。最后用一个最小可运行的端到端示例,把 + + 串成一条线,输出权重并打印预期年化收益、波动率与夏普比率。读完本节,你的电脑上应当能复现一份最优组合权重表。 内容来源:原项目源码 快速示例、 安装说明、 ,汉化并套用体系化模板。 学习目标 阅读完本节,你应当能够: 用 pip 完成 PyPortfolioOpt 的安装,知道源码安装的备用方式。
本节摘要:本节带你从零跑出第一个最优组合——把抽象的「四层架构」落到可执行代码上。先讲清安装方式:pip 一行命令,源码安装的备用方案,以及 Windows/macOS 上的 C++ 编译依赖。再讲清输入数据的规范——价格 DataFrame 的长宽格式、索引为日期、列为资产代码、值为复权收盘价。最后用一个最小可运行的端到端示例,把
mean_historical_return+sample_cov+EfficientFrontier.max_sharpe串成一条线,输出权重并打印预期年化收益、波动率与夏普比率。读完本节,你的电脑上应当能复现一份最优组合权重表。
内容来源:原项目源码
README.md快速示例、docs/index.rst安装说明、cookbook/2-Mean-Variance-Optimisation.ipynb,汉化并套用体系化模板。
阅读完本节,你应当能够:
最简单的方式是 pip:
pip install pyportfolioopt
PyPortfolioOpt 的核心依赖是 numpy、pandas、scipy、cvxpy、scikit-learn。pip 会自动装好。其中 cvxpy 是底层的凸优化建模语言,所有 EfficientFrontier 的求解都委托给它。
⚠️ Windows 用户注意:cvxpy 依赖 C++ 编译环境。Windows 上若装不上,需先装 Visual Studio Build Tools;macOS 上需先装 XCode Command Line Tools(
xcode-select --install)。具体见 cvxpy 官方安装文档。
若想用最新未发布版本,或想修改源码,可克隆仓库后本地安装:
git clone https://github.com/PyPortfolio/PyPortfolioOpt.git cd PyPortfolioOpt pip install .
若既要改源码又想全局 from pypfopt import x,用「可编辑模式」:
pip install -e git+https://github.com/pyportfolio/pyportfolioopt.git
作者推荐用依赖管理器。在 poetry 项目里:
poetry add pyportfolioopt
依赖管理器能锁定版本,避免日后环境漂移。生产环境强烈建议用这种方式。
PyPortfolioOpt 的所有收益/风险函数默认吃价格 DataFrame:
理想数据长这样(截自官方测试集 tests/resources/stock_prices.csv):
date XOM RRC BBY MA PFE JPM 2010-01-04 54.068794 51.300568 32.524055 22.062426 13.940202 35.175220 2010-01-05 54.279907 51.993038 33.349487 21.997149 13.741367 35.856571 2010-01-06 54.749043 51.690697 33.090542 22.081820 13.697187 36.053574 2010-01-07 54.577045 51.593170 33.616547 21.937523 13.645634 36.767757 2010-01-08 54.358093 52.597733 32.297466 21.945297 13.756095 36.677460
读取时记得把日期列解析成 index:
import pandas as pd df = pd.read_csv( "tests/resources/stock_prices.csv", parse_dates=True, index_col="date", )
💡 数据获取:官方 cookbook 用
yfinance库直接从雅虎财经下载,无需 API key:yf.download(tickers, period="max")["Close"]。教程示例可用它快速搭起数据。生产环境建议用 wind/tushare/聚宽等付费源,保证除权处理与数据质量。
数据就绪后,从估收益、估风险、求最优三步走。完整的最小示例:
import pandas as pd from pypfopt import EfficientFrontier, risk_models, expected_returns # 1. 读数据 df = pd.read_csv("tests/resources/stock_prices.csv", parse_dates=True, index_col="date") # 2. 估收益与风险 mu = expected_returns.mean_historical_return(df) # 均值历史收益 S = risk_models.sample_cov(df) # 样本协方差 # 3. 优化:最大夏普 ef = EfficientFrontier(mu, S) raw_weights = ef.max_sharpe() cleaned_weights = ef.clean_weights() # 4. 打印 for name, value in cleaned_weights.items(): print(f"{name}: {value:.4f}")
输出示例(实际数值随数据集变化):
GOOG: 0.0458 AAPL: 0.0674 FB: 0.2008 ... MA: 0.3287 PFE: 0.2039 SBUX: 0.0173
💡 clean_weights 干了啥:优化器输出的
raw_weights是OrderedDict,值带浮点误差。clean_weights()会把绝对值小于cutoff(默认1e-4)的权重置零,剩余保留rounding(默认 5)位小数。这让结果可读,也方便后续离散分配。设clean_weights(cutoff=1e-4, rounding=5)可调。
求出权重后,用 portfolio_performance 查看预期表现:
exp_return, volatility, sharpe = ef.portfolio_performance(verbose=True)
会打印:
Expected annual return: 29.9% Annual volatility: 21.8% Sharpe Ratio: 1.38
三个量的含义:
| 指标 | 公式 | 含义 |
|---|---|---|
| 预期年化收益 | w @ mu |
组合的期望年化收益(mu 已年化) |
| 年化波动率 | sqrt(wᵀ Σ w) |
组合收益的年化标准差,即风险 |
| 夏普比率 | (R_p - R_f) / σ |
单位风险的超额收益,越大越好 |
⚠️ 这是样本内表现:
portfolio_performance用的是与优化相同的 mu、Σ,因此是样本内(in-sample)估计,几乎一定好看。它不能代表未来真实表现。务必做样本外回测再下结论。
save_weights_to_file 把权重写入文件,支持三种格式:
ef.save_weights_to_file("weights.csv") # pd.Series.to_csv ef.save_weights_to_file("weights.json") # json.dump ef.save_weights_to_file("weights.txt") # str(dict)
连续权重(如 MA=0.3287)还要换算成「买几股」才算可下单的分配。PyPortfolioOpt 提供 DiscreteAllocation 把权重 + 最新价 + 总资金 转成整数股数:
from pypfopt.discrete_allocation import DiscreteAllocation, get_latest_prices latest_prices = get_latest_prices(df) da = DiscreteAllocation(cleaned_weights, latest_prices, total_portfolio_value=10000) allocation, leftover = da.greedy_portfolio() for name, value in allocation.items(): print(f"{name}: {value}") print(f"Funds remaining: ${leftover:.2f}")
输出:
MA: 19 PFE: 57 FB: 12 ... Funds remaining: $17.46
这是真实下单的依据。离散分配的两种算法(greedy_portfolio 与 lp_portfolio)会在第 9 章详讲。
pip install pyportfolioopt;Windows 装 VS Build Tools、macOS 装 XCode CLT 才能装上 cvxpy。mean_historical_return(df) → sample_cov(df) → EfficientFrontier(mu, S).max_sharpe()。clean_weights() 把极小值置零并四舍五入;portfolio_performance(verbose=True) 打印年化收益/波动率/夏普。save_weights_to_file 存三格式;DiscreteAllocation 把权重换算成买几股。下一节,我们把这套流程抽象成贯穿全书的「四层架构」——收益模型、风险模型、目标函数、优化器,看它们如何可替换地组装。