02 你的第一个量化实验 一、股票数据介绍1. 日线行情表每一行 一个交易日每一列 当天市场记录下来的一个数字列名英文含义开盘Open当天第一笔成交价最高High当天成交过的最高价最低Low当天成交过的最低价收盘Close当天最后一笔成交价最常用成交量Volume当天一共成交了多少股备注为什么最常用收盘价 因为收盘代表这一天「最终定价」研究涨跌、算收益率默认都用 Close。OHLCVOpen开盘价、High最高价、Low最低价、Close收盘价、Volume成交量。收涨日收盘价 ≥ 开盘价Close Open。这意味着当天股价整体是从低往高走的买方多头力量更强。在你的 OHLC 图中这一天显示为绿色。收跌日收盘价 开盘价Close Open。这意味着当天股价整体是从高往低走的卖方空头力量更强。在你的 OHLC 图中这一天显示为红色。2. Python 实现# 下载苹果 AAPL 最近约 1 年的日线数据 aapl yf.download(AAPL, period1y, progressFalse, multi_level_indexFalse) # 下载 aapl aapl.dropna() # 删掉有空值的行保证数据完整 print(数据形状行交易日列字段, aapl.shape) # 例如 (251, 5) print(\n前 5 行) # 提示下方表格 display(aapl.head()) # Jupyter 里美观显示表格前几行 print(\n各列含义速查) # 打印列名说明 for col in aapl.columns: # 遍历每一列的名字 print(f {col}) # 格式化打印# 配图1收盘价折线 成交量柱状图 fig, axes plt.subplots(2, 1, figsize(12, 7), sharexTrue, # 2行1列共用日期横轴 gridspec_kw{height_ratios: [3, 1]}) # 上图更高 axes[0].plot(aapl.index, aapl[Close], colortab:blue, linewidth1.2, labelClose Price) # 上图画折线 axes[0].set_ylabel(Price (USD)) # 设置上图纵轴 axes[0].set_title(Apple AAPL: Close Price and Volume (Real Market Data), fontsize14) # 设置上图标题 axes[0].legend(locupper left) # 显示上图图例 axes[0].grid(True, alpha0.3) # 上图显示网格 axes[1].bar(aapl.index, aapl[Volume], width0.8, colorgray, alpha0.5, labelVolume) # 下图画柱状图 axes[1].set_ylabel(Volume (Shares)) # 设置下图纵轴 axes[1].legend(locupper left) # 显示下图图例 axes[1].set_xlabel(Date) # 设置下图横轴日期 axes[1].grid(True, alpha0.3) # 下图显示网格 plt.tight_lay# 配图2最近8天 OHLC 示意图 sample aapl.tail(8).copy() # 取最后 8 个交易日 dates range(len(sample)) # 0,1,...,7 用作横轴位置 fig, ax plt.subplots(figsize(12, 5)) # 创建子图 for i, (idx, row) in enumerate(sample.iterrows()): # 逐行遍历每一天 o, h, l, c row[Open], row[High], row[Low], row[Close] # 开高低收 color tab:red if c o else tab:green # 收跌红色、收涨绿色 ax.vlines(i, l, h, colorcolor, linewidth2, alpha0.85) # 竖线最低到最高 ax.hlines(o, i - 0.15, i 0.15, colorcolor, linewidth2) # 开盘价短横线 ax.hlines(c, i - 0.15, i 0.15, colorcolor, linewidth3) # 收盘价粗横线 ax.set_xticks(dates) # 设置横轴刻度位置 ax.set_xticklabels([d.strftime(%m-%d) for d in sample.index], rotation45) # 日期标签 ax.set_ylabel(Price (USD)) # 设置子图纵轴英文 ax.set_title(Last 8 Trading Days: Vertical Lines High↔Low, Short Dashes Open / Close (Thicker Close), fontsize13) # 设置子图标题 ax.grid(True, axisy, alpha0.3) # 显示网格 from matplotlib.lines import Line2D # 自定义图例用的小线段 legend_elements [ # 自定义图例项 Line2D([0], [0], colortab:green, linewidth2, labelUp Day (Close ≥ Open)), # 线宽 Line2D([0], [0], colortab:red, linewidth2, labelDown Day (Close Open)), # 线宽 ] # 数组拼接结束 ax.legend(handleslegend_elements, locupper left) # 显示图例 plt.tight_layout() # 自动调整子图间距避免标签被裁切 plt.show() # 在 Notebook 里显示图片 print(小贴士一天之内价格一定满足 Low ≤ Open, Close ≤ High) # 打印小贴士二、什么是收益率涨跌 价格变化收益率 价格变化占昨天价格的比例相对自己本金涨了多少日收益率公式设昨天收盘价为今天收盘价为日收益率为。pandas 计算相邻两天的收益率df[日收益率] df[Close].pct_change()pct_change() 做的正是第一行没有「昨天」所以是空值NaN# 用 pandas 计算整列日收益率 df aapl[[Close]].copy() # 只保留收盘价一列 df[日收益率] df[Close].pct_change() # 今天相对昨天的涨跌比例 print(最近 10 天的收盘价与日收益率) # 打印输出 display(df.tail(10)) # 在 Notebook 中美观显示表格 # 手算最后一天和 pct_change 对照 row_today df.iloc[-1] # 最后一行今天 row_yesterday df.iloc[-2] # 倒数第二行昨天 manual_r (row_today[Close] - row_yesterday[Close]) / row_yesterday[Close] # 手算收益率用于验证 print(f\n验证最后一天手算 {manual_r:.4%}pct_change {row_today[日收益率]:.4%}) # 对照手算与 pandas 结果三、可视化收益率日收益率曲线 —— 每天涨跌幅度一目了然直方图Histogram —— 大部分日子涨跌集中在哪个区间有没有「极端大涨跌」# 日收益率曲线 直方图 rets df[日收益率].dropna() # 去掉第一天的 NaN fig, axes plt.subplots(1, 2, figsize(14, 5)) # 1行2列 axes[0].plot(rets.index, rets.values, colorsteelblue, linewidth0.9, alpha0.85) # 左图画折线 axes[0].axhline(0, colorblack, linewidth0.8, linestyle--) # 零轴参考线 axes[0].set_title(Apple AAPL: Daily Return Curve, fontsize13) # 设置上图标题日收益率曲线 axes[0].set_xlabel(Date) # 设置横轴 axes[0].set_ylabel(Daily Return) # 设置纵轴 axes[0].grid(True, alpha0.3) # 上图显示网格 axes[1].hist(rets.values, bins40, colorsteelblue, edgecolorwhite, alpha0.85) # 画直方图 axes[1].axvline(0, colorblack, linewidth0.8, linestyle--) # 右图画垂直参考线 axes[1].axvline(rets.mean(), colororange, linewidth2, labelfMean {rets.mean():.2%}) # 求平均值 axes[1].set_title(Daily Return Distribution (Histogram), fontsize13) # 设置下图标题日收益率分布 axes[1].set_xlabel(Daily Return) # 设置横轴日期 axes[1].set_ylabel(Frequency (Days)) # 设置纵轴 axes[1].legend() # 显示下图图例 axes[1].grid(True, alpha0.3) # 下图显示网格 plt.tight_layout() # 自动调整子图间距避免标签被裁切 plt.show() # 在 Notebook 里显示图片 print(f样本天数: {len(rets)}) # 打印统计结果 print(f平均日收益率: {rets.mean():.3%}正整体偏多涨) # 格式化打印 print(f日收益率标准差: {rets.std():.3%}越大波动越剧烈) # 格式化打印# 累计收益率曲线 cum_return (1 rets).cumprod() - 1 # 每天 (1r) 连乘再减1得到累计涨跌 plt.figure(figsize(12, 4)) # 创建画布 plt.plot(cum_return.index, cum_return.values * 100, colortab:purple, linewidth1.5) # 画折线图 plt.axhline(0, colorgray, linestyle--, linewidth0.8) # 画水平参考线 plt.title(Apple AAPL: Cumulative Return Curve (%), fontsize14) # 设置图标题累计收益率曲线 plt.xlabel(Date) # 设置横轴标签 plt.ylabel(Cumulative Return (%)) # 设置纵轴标签累计收益率 plt.grid(True, alpha0.3) # 显示网格线 plt.tight_layout() # 自动调整子图间距避免标签被裁切 plt.show() # 在 Notebook 里显示图片 print(f这段区间累计涨跌: {cum_return.iloc[-1]:.2%}) # 打印价格统计四、小实验谁波动更大同样是科技股苹果 AAPL、特斯拉 TSLA、英伟达 NVDA 的「脾气」一样吗我们用日收益率的标准差衡量波动标准差越大涨跌越猛。# 小实验下载三只股票并算波动 tickers { # 要对比的股票列表 AAPL: Apple, # 苹果 TSLA: Tesla, # 特斯拉 NVDA: NVIDIA, # 英伟达 } period 1y # 时间长度可改成 6mo、2y all_rets {} # 用字典存每只股票的中文名 → 日收益率序列 for symbol, name in tickers.items(): # 逐只股票下载 data yf.download(symbol, periodperiod, progressFalse, multi_level_indexFalse).dropna() # 下载股票日线行情 all_rets[name] data[Close].pct_change().dropna() # 只关心收盘价涨跌 print(f{name} ({symbol}): {len(all_rets[name])} 个交易日) # 打印统计结果 vol pd.Series({name: s.std() for name, s in all_rets.items()}).sort_values(ascendingFalse) # 求标准差波动大小 print(\n 日收益率波动标准差越大越猛) # 打印分隔线或结论 for name, v in vol.items(): # 代码块开始 print(f {name}: {v:.3%}) # 格式化打印# 三只股票收益率对比图 fig, axes plt.subplots(1, 2, figsize(14, 5)) # 创建子图 colors [tab:blue, tab:orange, tab:green] # 各曲线颜色 for (name, series), c in zip(all_rets.items(), colors): # 逐只股票画曲线 axes[0].plot(series.index, series.values, labelname, alpha0.75, linewidth0.8) # 左图画折线 axes[0].axhline(0, colorblack, linestyle--, linewidth0.6) # 画参考线 axes[0].set_title(Daily Return Comparison, fontsize13) # 设置标题日收益率对比 axes[0].set_xlabel(Date) # 横轴 axes[0].set_ylabel(Daily Return) # 纵轴 axes[0].legend() # 显示上图图例 axes[0].grid(True, alpha0.3) # 上图显示网格 axes[1].bar(vol.index, vol.values * 100, colorcolors[: len(vol)], edgecolorwhite) # 右图画柱状图 axes[1].set_title(Volatility Comparison (Std Dev %), fontsize13) # 设置下图标题波动大小对比标准差 % axes[1].set_ylabel(Standard Deviation (%)) # 设置纵轴 axes[1].grid(True, axisy, alpha0.3) # 下图显示网格 for i, v in enumerate(vol.values): # 在柱顶标注数值 axes[1].text(i, v * 100 0.02, f{v:.2%}, hacenter, fontsize11) # 字号 plt.tight_layout() # 自动调整子图间距避免标签被裁切 plt.show() # 在 Notebook 里显示图片 winner vol.index[0] # 波动最大的股票 print(f\n在本实验设定下{period} 日线波动最大的是{winner}) # 格式化打印# 三只股票 Histogram 并排对比 fig, axes plt.subplots(1, 3, figsize(15, 4), shareyTrue) # 创建子图 for ax, (name, series), c in zip(axes, all_rets.items(), colors): # 逐只股票画直方图 ax.hist(series.values, bins35, colorc, alpha0.75, edgecolorwhite) # 透明度 ax.axvline(0, colorblack, linestyle--, linewidth0.6) # 画垂直参考线 ax.set_title(f{name}\nσ {series.std():.2%}) # 求标准差波动大小 ax.set_xlabel(Daily Return) # 设置子图横轴日收益率 axes[0].set_ylabel(Frequency (Days)) # 设置上图纵轴 fig.suptitle(Comparison of Daily Return Histograms for Three Stocks, fontsize14, y1.02) # 整张图的总标题三只股票日收益率 Histogram 对比 plt.tight_layout() # 自动调整子图间距避免标签被裁切 plt.show() # 在 Notebook 里显示图片