yfinance进阶指南:如何用Python分析多只股票的基本面并生成对比报告
yfinance进阶指南:如何用Python分析多只股票的基本面并生成对比报告
在投资分析和量化交易领域,能够同时评估多只股票的表现是每个专业投资者的必备技能。本文将带你深入探索如何利用Python的yfinance库,构建一个高效的多股票分析系统,从数据获取到可视化呈现,再到生成专业的对比报告。
1. 环境准备与数据获取
1.1 安装必要库
首先确保你的Python环境已经安装了以下核心库:
pip install yfinance pandas numpy matplotlib seaborn对于更复杂的分析,我们还会用到:
pip install plotly scipy statsmodels1.2 多股票数据批量获取
yfinance提供了简洁的接口来同时获取多只股票的数据。以下代码演示如何一次性获取苹果(AAPL)、微软(MSFT)和谷歌(GOOGL)的基础信息:
import yfinance as yf import pandas as pd tickers = ["AAPL", "MSFT", "GOOGL"] data = yf.Tickers(tickers) # 获取基本信息 info_data = {ticker: data.tickers[ticker].info for ticker in tickers}提示:当获取多只股票数据时,建议使用异常处理来应对可能的网络问题或数据缺失情况。
2. 关键财务指标对比分析
2.1 构建财务指标对比表
我们将从以下几个维度对比分析:
- 估值指标:市盈率、市净率、市销率
- 盈利能力:ROE、毛利率、净利率
- 财务健康:资产负债率、流动比率
- 股息信息:股息率、派息比率
def extract_key_metrics(info_dict, ticker): metrics = { 'Ticker': ticker, 'Company Name': info_dict.get('longName', 'N/A'), 'Market Cap (B)': round(info_dict.get('marketCap', 0)/1e9, 2), 'P/E (TTM)': info_dict.get('trailingPE', 'N/A'), 'P/E (Forward)': info_dict.get('forwardPE', 'N/A'), 'P/B': info_dict.get('priceToBook', 'N/A'), 'ROE (%)': round(info_dict.get('returnOnEquity', 0)*100, 2) if info_dict.get('returnOnEquity') else 'N/A', 'Debt/Equity': info_dict.get('debtToEquity', 'N/A'), 'Dividend Yield (%)': round(info_dict.get('dividendYield', 0)*100, 2) if info_dict.get('dividendYield') else 'N/A', 'Profit Margin (%)': round(info_dict.get('profitMargins', 0)*100, 2) if info_dict.get('profitMargins') else 'N/A' } return metrics # 创建对比DataFrame comparison_df = pd.DataFrame([extract_key_metrics(info_data[ticker], ticker) for ticker in tickers])2.2 可视化财务对比
使用热力图展示关键指标的相对表现:
import seaborn as sns import matplotlib.pyplot as plt # 选择需要可视化的指标 viz_metrics = comparison_df.set_index('Ticker')[['P/E (TTM)', 'P/B', 'ROE (%)', 'Debt/Equity', 'Dividend Yield (%)']] plt.figure(figsize=(12, 6)) sns.heatmap(viz_metrics.astype(float), annot=True, cmap='YlGnBu', fmt='.2f', linewidths=.5) plt.title('关键财务指标对比') plt.show()3. 历史表现对比分析
3.1 获取历史价格数据
# 获取5年历史数据 hist_data = yf.download(tickers, period="5y", group_by='ticker') # 整理收盘价数据 close_prices = pd.DataFrame({ticker: hist_data[ticker]['Close'] for ticker in tickers})3.2 计算累积收益率
# 计算标准化收益率 normalized_returns = close_prices / close_prices.iloc[0] # 可视化 plt.figure(figsize=(12, 6)) for ticker in tickers: plt.plot(normalized_returns.index, normalized_returns[ticker], label=ticker) plt.title('5年累积收益率对比 (基准化)') plt.ylabel('累积收益率') plt.legend() plt.grid(True) plt.show()3.3 风险指标计算
# 计算年化波动率 annual_volatility = close_prices.pct_change().std() * (252 ** 0.5) # 计算最大回撤 def max_drawdown(series): cum_max = series.cummax() drawdown = (series - cum_max) / cum_max return drawdown.min() max_drawdowns = close_prices.apply(max_drawdown) risk_metrics = pd.DataFrame({ 'Annual Volatility': annual_volatility, 'Max Drawdown': max_drawdowns })4. 生成专业对比报告
4.1 创建多页PDF报告
使用Matplotlib的PdfPages功能生成包含所有分析的PDF报告:
from matplotlib.backends.backend_pdf import PdfPages def generate_report(filename): with PdfPages(filename) as pdf: # 封面页 fig = plt.figure(figsize=(11, 8.5)) plt.text(0.5, 0.5, '股票对比分析报告\n\n'+pd.Timestamp.now().strftime('%Y-%m-%d'), ha='center', va='center', size=24) plt.axis('off') pdf.savefig(fig) plt.close() # 财务指标对比页 fig, ax = plt.subplots(figsize=(11, 8)) ax.axis('tight') ax.axis('off') table = ax.table(cellText=comparison_df.values, colLabels=comparison_df.columns, cellLoc='center', loc='center') table.auto_set_font_size(False) table.set_fontsize(10) table.scale(1.2, 1.2) pdf.savefig(fig) plt.close() # 添加其他分析图表... print(f"报告已生成: {filename}") generate_report('stock_comparison_report.pdf')4.2 交互式HTML报告
对于更现代的展示方式,可以使用Plotly生成交互式HTML报告:
import plotly.express as px import plotly.graph_objects as go from plotly.subplots import make_subplots # 创建交互式图表 fig = make_subplots(rows=2, cols=1, subplot_titles=('累积收益率对比', '关键指标对比')) for ticker in tickers: fig.add_trace(go.Scatter(x=normalized_returns.index, y=normalized_returns[ticker], name=ticker), row=1, col=1) fig.add_trace(go.Bar(x=comparison_df['Ticker'], y=comparison_df['ROE (%)'], name='ROE (%)'), row=2, col=1) fig.update_layout(height=800, title_text="股票对比分析") fig.write_html("interactive_report.html")5. 高级分析技巧
5.1 相关性分析
# 计算每日收益率相关性 returns = close_prices.pct_change().dropna() correlation_matrix = returns.corr() plt.figure(figsize=(8, 6)) sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', vmin=-1, vmax=1) plt.title('每日收益率相关性矩阵') plt.show()5.2 投资组合模拟
# 等权重投资组合 weights = np.array([1/len(tickers)] * len(tickers)) portfolio_returns = (returns * weights).sum(axis=1) # 计算累积组合收益 cumulative_portfolio = (1 + portfolio_returns).cumprod() plt.figure(figsize=(12, 6)) plt.plot(cumulative_portfolio.index, cumulative_portfolio, label='等权重组合', linewidth=2) for ticker in tickers: plt.plot(normalized_returns.index, normalized_returns[ticker], alpha=0.3, label=ticker) plt.title('投资组合表现对比') plt.legend() plt.show()5.3 基本面评分系统
创建一个简单的量化评分系统:
def calculate_score(row): score = 0 # ROE越高越好 if isinstance(row['ROE (%)'], (int, float)): score += row['ROE (%)'] * 0.3 # 负债率越低越好 if isinstance(row['Debt/Equity'], (int, float)): score -= row['Debt/Equity'] * 0.2 # 股息率越高越好 if isinstance(row['Dividend Yield (%)'], (int, float)): score += row['Dividend Yield (%)'] * 0.1 # 利润率越高越好 if isinstance(row['Profit Margin (%)'], (int, float)): score += row['Profit Margin (%)'] * 0.2 # 市盈率越低越好 if isinstance(row['P/E (TTM)'], (int, float)): score -= row['P/E (TTM)'] * 0.05 return round(score, 2) comparison_df['Score'] = comparison_df.apply(calculate_score, axis=1) comparison_df = comparison_df.sort_values('Score', ascending=False)在实际项目中,我发现将技术指标分析与基本面数据结合使用时,往往能发现更有价值的投资机会。例如,当一只股票的基本面评分较高但近期价格出现非基本面驱动的下跌时,可能是一个不错的买入机会。
