第三章:数据获取入门——用Python抓免费行情
做量化交易,数据就是你的弹药库。没有数据,再牛的策略也是纸上谈兵。
这一章,咱们就动手解决一个最实际的问题:怎么用Python免费拿到靠谱的行情数据。我会带你走两条路——Yahoo Finance和东方财富,顺便把数据清洗的基础也一并搞定。
3.1 为什么选这两个数据源?
市面上免费数据源不少,但我个人最常用的是这两个:
| 数据源 | 优点 | 缺点 |
|---|---|---|
| Yahoo Finance | 全球市场覆盖广,API稳定,历史数据全 | 国内访问偶尔抽风,A股数据有时延迟 |
| 东方财富 | A股数据实时性好,接口免费,文档多 | 海外市场数据少,接口偶尔变动 |
你想想看,做跨品种套利,你既可能交易A股,也可能涉及港股或美股。两个数据源互补,基本能覆盖大部分场景。
3.2 用Yahoo Finance获取数据
Yahoo Finance的接口,说白了就是通过yfinance这个库来调。安装很简单:
pip install yfinance
然后写几行代码就能拿到数据:
import yfinance as yf
# 获取贵州茅台的历史数据
maotai = yf.download('600519.SS', start='2023-01-01', end='2023-12-31')
print(maotai.head())
这里要注意,A股代码后面要加后缀:.SS代表上海,.SZ代表深圳。港股加.HK,美股直接写代码就行。
我在项目中遇到过一个问题:Yahoo Finance偶尔会返回空数据。尤其是节假日或者停牌期间。这时候别慌,加个重试机制就好:
import time
from yfinance import download
def safe_download(ticker, start, end, retries=3):
for i in range(retries):
try:
data = download(ticker, start=start, end=end)
if not data.empty:
return data
time.sleep(2)
except Exception as e:
print(f"第{i+1}次尝试失败:{e}")
time.sleep(5)
return None
3.3 用东方财富获取A股数据
东方财富的接口更接地气。我用的是akshare这个库,它封装了东方财富的底层API:
pip install akshare
获取个股历史行情:
import akshare as ak
# 获取贵州茅台日线数据
maotai_daily = ak.stock_zh_a_hist(symbol="600519", period="daily",
start_date="20230101", end_date="20231231")
print(maotai_daily.head())
东方财富返回的数据格式更规整,列名都是中文。但有个坑——日期格式是YYYYMMDD,不是标准的YYYY-MM-DD。后面清洗的时候要处理一下。
我个人更喜欢东方财富的一点:它支持获取实时行情。比如拿当前盘口的买卖五档:
# 获取实时行情
realtime = ak.stock_zh_a_spot_em()
# 筛选特定股票
maotai_realtime = realtime[realtime['代码'] == '600519']
print(maotai_realtime[['名称', '最新价', '涨跌幅']])
3.4 数据清洗基础——让数据变得可用
拿到原始数据后,你会发现一堆问题:缺失值、格式不对、列名混乱……
嗯,这里要注意,数据清洗不是可选项,是必选项。我见过太多人拿着脏数据跑策略,结果回测曲线漂亮得像假的一样——其实就是假的。
3.4.1 处理缺失值
Yahoo Finance返回的数据,遇到停牌日会直接跳过。但东方财富可能会返回NaN。我的处理原则是:
- 连续缺失不超过3天:用前向填充(ffill)
- 超过3天:直接删除该行
- 开盘价缺失:用前一天的收盘价替代
import pandas as pd
def clean_missing(data):
# 前向填充,最多填充3个缺失值
data = data.fillna(method='ffill', limit=3)
# 删除仍有缺失的行
data = data.dropna()
return data
3.4.2 统一列名和格式
不同数据源的列名不一样。Yahoo Finance是英文,东方财富是中文。我建议统一成英文小写:
def standardize_columns(data, source='yahoo'):
if source == 'yahoo':
data.columns = ['open', 'high', 'low', 'close', 'adj_close', 'volume']
elif source == 'eastmoney':
data.columns = ['date', 'open', 'close', 'high', 'low', 'volume',
'amount', 'amplitude', 'pct_change', 'change', 'turnover']
return data
3.4.3 日期处理
日期格式不统一,是跨品种套利的大忌。你想想看,如果A股和港股的时间轴对不上,计算价差就会出错。
def clean_date(data, date_col='date'):
data[date_col] = pd.to_datetime(data[date_col])
data = data.set_index(date_col)
data = data.sort_index()
return data
3.5 实战:整合两个数据源
下面是我在实际项目中用的一个整合函数。它从两个数据源分别拿数据,然后合并清洗:
def get_unified_data(ticker, start, end, source='auto'):
"""
获取统一格式的行情数据
source: 'yahoo', 'eastmoney', 'auto'
"""
if source == 'yahoo' or (source == 'auto' and ticker.endswith(('.SS', '.SZ', '.HK'))):
data = safe_download(ticker, start, end)
data = standardize_columns(data, 'yahoo')
else:
# 东方财富不需要后缀
code = ticker.replace('.SS', '').replace('.SZ', '')
data = ak.stock_zh_a_hist(symbol=code, period="daily",
start_date=start.replace('-', ''),
end_date=end.replace('-', ''))
data = standardize_columns(data, 'eastmoney')
data = clean_date(data)
data = clean_missing(data)
return data
这个函数我用了快两年,基本没出过问题。唯一要注意的是,东方财富的接口偶尔会更新,导致参数变化。建议你定期检查akshare的版本。
3.6 本章知识体系
下面这张图,帮你理清数据获取和清洗的完整流程:
说白了,数据获取就三步:选源 → 抓取 → 清洗。每一步都有坑,但踩过一次就记住了。
好了,这一章的内容就到这里。数据到手了,下一章咱们就可以开始做真正的跨品种套利分析了。
公众号:蓝海资料掘金营,微信deep3321