In [1]:
Copied!
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import yfinance as yf
from pathlib import Path
# 数据存储路径
DATA_DIR = Path('../datasets')
DATA_DIR.mkdir(exist_ok=True)
print('准备就绪 ✅')
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import yfinance as yf
from pathlib import Path
# 数据存储路径
DATA_DIR = Path('../datasets')
DATA_DIR.mkdir(exist_ok=True)
print('准备就绪 ✅')
准备就绪 ✅
In [2]:
Copied!
import matplotlib.pyplot as plt
# 1. 设置系统自带的中文字体(这里使用黑体 SimHei)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 如果你想用微软雅黑,可以改成 ['Microsoft YaHei']
# 2. 解决更换字体后,负号(-)显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False
import matplotlib.pyplot as plt
# 1. 设置系统自带的中文字体(这里使用黑体 SimHei)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 如果你想用微软雅黑,可以改成 ['Microsoft YaHei']
# 2. 解决更换字体后,负号(-)显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False
1. yfinance — 美股数据¶
In [3]:
Copied!
# ===== 单只股票 =====
ticker = yf.Ticker('AAPL')
# 日线历史数据
hist = ticker.history(start='2020-01-01', end='2024-01-01')
print('AAPL 历史数据字段:', hist.columns.tolist())
print(f'数据量: {len(hist)} 行')
hist.tail(3)
# ===== 单只股票 =====
ticker = yf.Ticker('AAPL')
# 日线历史数据
hist = ticker.history(start='2020-01-01', end='2024-01-01')
print('AAPL 历史数据字段:', hist.columns.tolist())
print(f'数据量: {len(hist)} 行')
hist.tail(3)
AAPL 历史数据字段: ['Open', 'High', 'Low', 'Close', 'Volume', 'Dividends', 'Stock Splits'] 数据量: 1006 行
Out[3]:
| Open | High | Low | Close | Volume | Dividends | Stock Splits | |
|---|---|---|---|---|---|---|---|
| Date | |||||||
| 2023-12-27 00:00:00-05:00 | 190.510890 | 191.510500 | 189.125276 | 191.164093 | 48087700 | 0.0 | 0.0 |
| 2023-12-28 00:00:00-05:00 | 192.143900 | 192.658558 | 191.183873 | 191.589661 | 34049900 | 0.0 | 0.0 |
| 2023-12-29 00:00:00-05:00 | 191.906385 | 192.401245 | 189.758698 | 190.550476 | 42672100 | 0.0 | 0.0 |
In [4]:
Copied!
# ===== 字段说明 =====
field_desc = {
'Open': '开盘价 — 当日第一笔成交价',
'High': '最高价 — 当日最高成交价',
'Low': '最低价 — 当日最低成交价',
'Close': '收盘价 — 当日最后成交价(原始)',
'Volume':'成交量 — 当日总成交股数',
'Dividends': '分红 — 当日每股分红金额',
'Stock Splits': '股票拆分倍数(2=一股变两股)'
}
for k, v in field_desc.items():
if k in hist.columns:
print(f' {k:<15}: {v}')
# ===== 字段说明 =====
field_desc = {
'Open': '开盘价 — 当日第一笔成交价',
'High': '最高价 — 当日最高成交价',
'Low': '最低价 — 当日最低成交价',
'Close': '收盘价 — 当日最后成交价(原始)',
'Volume':'成交量 — 当日总成交股数',
'Dividends': '分红 — 当日每股分红金额',
'Stock Splits': '股票拆分倍数(2=一股变两股)'
}
for k, v in field_desc.items():
if k in hist.columns:
print(f' {k:<15}: {v}')
Open : 开盘价 — 当日第一笔成交价 High : 最高价 — 当日最高成交价 Low : 最低价 — 当日最低成交价 Close : 收盘价 — 当日最后成交价(原始) Volume : 成交量 — 当日总成交股数 Dividends : 分红 — 当日每股分红金额 Stock Splits : 股票拆分倍数(2=一股变两股)
In [5]:
Copied!
# ===== 多只股票批量下载 =====
tickers = ['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'SPY']
prices = yf.download(tickers, start='2020-01-01', end='2024-01-01',
progress=False)['Close']
# 标准化为基准100(便于比较)
normalized = prices / prices.iloc[0] * 100
fig, ax = plt.subplots(figsize=(12, 5))
for col in normalized.columns:
ax.plot(normalized.index, normalized[col], label=col, linewidth=1.3)
ax.axhline(100, color='gray', linestyle='--', alpha=0.5)
ax.set_title('科技股 vs SPY 标准化收益对比 (基准=100)', fontsize=13)
ax.set_ylabel('标准化价格')
ax.legend()
ax.grid(alpha=0.3)
plt.tight_layout()
plt.show()
# 保存到 datasets
prices.to_csv(DATA_DIR / 'sp500_sample.csv')
print(f'已保存至 {DATA_DIR / "sp500_sample.csv"}')
# ===== 多只股票批量下载 =====
tickers = ['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'SPY']
prices = yf.download(tickers, start='2020-01-01', end='2024-01-01',
progress=False)['Close']
# 标准化为基准100(便于比较)
normalized = prices / prices.iloc[0] * 100
fig, ax = plt.subplots(figsize=(12, 5))
for col in normalized.columns:
ax.plot(normalized.index, normalized[col], label=col, linewidth=1.3)
ax.axhline(100, color='gray', linestyle='--', alpha=0.5)
ax.set_title('科技股 vs SPY 标准化收益对比 (基准=100)', fontsize=13)
ax.set_ylabel('标准化价格')
ax.legend()
ax.grid(alpha=0.3)
plt.tight_layout()
plt.show()
# 保存到 datasets
prices.to_csv(DATA_DIR / 'sp500_sample.csv')
print(f'已保存至 {DATA_DIR / "sp500_sample.csv"}')
已保存至 ..\datasets\sp500_sample.csv
2. A 股数据获取方案¶
对于 A 股,我们推荐两个优秀的数据源:
- adata:免费开源,专注 A 股,采用多数据源融合,接口设计非常人性化。
- AKShare:功能极其强大,涵盖了几乎所有公开的金融数据。
2.1 使用 adata 获取行情¶
In [6]:
Copied!
try:
import adata
# 1. 获取所有股票代码简表
all_stocks = adata.stock.info.all_code()
print(f'当前 A 股共有 {len(all_stocks)} 只股票/指数')
# 2. 获取单只股票行情(以贵州茅台为例)
# k_type: 1.日;2.周;3.月
# adjust: 0.不复权;1.前复权;2.后复权
mt_df = adata.stock.market.get_market(stock_code='600519', start_date='2022-01-01', k_type=1, adjust=1)
print('adata 茅台数据样例:')
mt_df['trade_date'] = pd.to_datetime(mt_df['trade_date'])
mt_df.set_index('trade_date', inplace=True)
# 保存
mt_df[['open', 'high', 'low', 'close', 'volume']].to_csv(DATA_DIR / 'adata_mt.csv')
print(f'已保存 {len(mt_df)} 条数据至 adata_mt.csv')
mt_df.head()
except ImportError:
print('⚠️ adata 未安装,请运行: pip install adata')
except Exception as e:
print(f'获取数据出错: {e}')
try:
import adata
# 1. 获取所有股票代码简表
all_stocks = adata.stock.info.all_code()
print(f'当前 A 股共有 {len(all_stocks)} 只股票/指数')
# 2. 获取单只股票行情(以贵州茅台为例)
# k_type: 1.日;2.周;3.月
# adjust: 0.不复权;1.前复权;2.后复权
mt_df = adata.stock.market.get_market(stock_code='600519', start_date='2022-01-01', k_type=1, adjust=1)
print('adata 茅台数据样例:')
mt_df['trade_date'] = pd.to_datetime(mt_df['trade_date'])
mt_df.set_index('trade_date', inplace=True)
# 保存
mt_df[['open', 'high', 'low', 'close', 'volume']].to_csv(DATA_DIR / 'adata_mt.csv')
print(f'已保存 {len(mt_df)} 条数据至 adata_mt.csv')
mt_df.head()
except ImportError:
print('⚠️ adata 未安装,请运行: pip install adata')
except Exception as e:
print(f'获取数据出错: {e}')
⚠️ adata 未安装,请运行: pip install adata
2.2 使用 AKShare (可选备选)¶
In [7]:
Copied!
try:
import akshare as ak
# 获取贵州茅台(600519)日线数据
mao_tai = ak.stock_zh_a_hist(
symbol='600519',
period='daily',
start_date='20220101',
end_date='20240101',
adjust='qfq' # 前复权
)
mao_tai = mao_tai.rename(columns={
'日期': 'Date', '开盘': 'Open', '最高': 'High',
'最低': 'Low', '收盘': 'Close', '成交量': 'Volume'
})
mao_tai['Date'] = pd.to_datetime(mao_tai['Date'])
mao_tai = mao_tai.set_index('Date')
# 保存
mao_tai[['Open', 'High', 'Low', 'Close', 'Volume']].to_csv(DATA_DIR / 'stock_daily.csv')
print(f'已保存 {len(mao_tai)} 条 AKShare 数据')
mao_tai.tail(3)
except ImportError:
print('⚠️ akshare 未安装')
except Exception as e:
print(f'AKShare 获取失败: {e}')
try:
import akshare as ak
# 获取贵州茅台(600519)日线数据
mao_tai = ak.stock_zh_a_hist(
symbol='600519',
period='daily',
start_date='20220101',
end_date='20240101',
adjust='qfq' # 前复权
)
mao_tai = mao_tai.rename(columns={
'日期': 'Date', '开盘': 'Open', '最高': 'High',
'最低': 'Low', '收盘': 'Close', '成交量': 'Volume'
})
mao_tai['Date'] = pd.to_datetime(mao_tai['Date'])
mao_tai = mao_tai.set_index('Date')
# 保存
mao_tai[['Open', 'High', 'Low', 'Close', 'Volume']].to_csv(DATA_DIR / 'stock_daily.csv')
print(f'已保存 {len(mao_tai)} 条 AKShare 数据')
mao_tai.tail(3)
except ImportError:
print('⚠️ akshare 未安装')
except Exception as e:
print(f'AKShare 获取失败: {e}')
⚠️ akshare 未安装
3. 宏观数据 — 市场的“背景板”¶
为什么量化也得看宏观?
QuantEcon 强调经济环境对金融资产的底层约束。例如,当 10 年期美债收益率 飙升时,科技股往往会承压,因为资金的折现成本变高了。
我们可以运行如下代码(使用 yfinance)获取关键宏观代理指标:
^TNX: CBOE 10 Year Treasury Note Yield(10年期美债收益率)^VIX: CBOE Volatility Index(恐慌指数)GC=F: Gold Futures(黄金期货,反映避险情绪)
In [8]:
Copied!
# 获取 10 年期美债收益率和 VIX 数据
macro_data = yf.download(['^TNX', '^VIX'], start='2020-01-01', end='2024-01-01', progress=False)['Close']
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8), sharex=True)
ax1.plot(macro_data.index, macro_data['^TNX'], color='darkblue', label='10 Year Treasury Yield (%)')
ax1.set_title("无风险利率走势 (10Y Yield)")
ax1.legend()
ax1.grid(alpha=0.3)
ax2.plot(macro_data.index, macro_data['^VIX'], color='darkred', label='VIX (Market Fear)')
ax2.set_title("市场恐慌程度 (VIX)")
ax2.legend()
ax2.grid(alpha=0.3)
plt.tight_layout()
plt.show()
print("宏观数据获取成功!这些数据通常作为因子的环境‘过滤器’使用。")
# 获取 10 年期美债收益率和 VIX 数据
macro_data = yf.download(['^TNX', '^VIX'], start='2020-01-01', end='2024-01-01', progress=False)['Close']
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8), sharex=True)
ax1.plot(macro_data.index, macro_data['^TNX'], color='darkblue', label='10 Year Treasury Yield (%)')
ax1.set_title("无风险利率走势 (10Y Yield)")
ax1.legend()
ax1.grid(alpha=0.3)
ax2.plot(macro_data.index, macro_data['^VIX'], color='darkred', label='VIX (Market Fear)')
ax2.set_title("市场恐慌程度 (VIX)")
ax2.legend()
ax2.grid(alpha=0.3)
plt.tight_layout()
plt.show()
print("宏观数据获取成功!这些数据通常作为因子的环境‘过滤器’使用。")
宏观数据获取成功!这些数据通常作为因子的环境‘过滤器’使用。
🎯 练习¶
- 下载你感兴趣的 5 只股票,绘制标准化收益对比图。
- 使用
adata或者yfinance获取单只股票数据并保存为 CSV。 - 获取黄金期货(
GC=F)数据,观察它在 2020 年市场大恐慌期间的表现。
下一节 → 02_data_cleaning.ipynb
In [ ]:
Copied!