第三章:数据获取入门——用Python抓免费行情

做量化交易,数据就是你的弹药库。没有数据,再牛的策略也是纸上谈兵。

这一章,咱们就动手解决一个最实际的问题:怎么用Python免费拿到靠谱的行情数据。我会带你走两条路——Yahoo Finance和东方财富,顺便把数据清洗的基础也一并搞定。

3.1 为什么选这两个数据源?

市面上免费数据源不少,但我个人最常用的是这两个:

数据源 优点 缺点
Yahoo Finance 全球市场覆盖广,API稳定,历史数据全 国内访问偶尔抽风,A股数据有时延迟
东方财富 A股数据实时性好,接口免费,文档多 海外市场数据少,接口偶尔变动

你想想看,做跨品种套利,你既可能交易A股,也可能涉及港股或美股。两个数据源互补,基本能覆盖大部分场景。

我的习惯:平时开发用Yahoo Finance做回测,实盘监控用东方财富。各取所长。

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
避坑指南:我曾经因为网络问题,连续重试了10次都没拿到数据。后来发现是代理设置的问题。建议你在代码里加个超时控制,别让程序卡死。

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 本章知识体系

下面这张图,帮你理清数据获取和清洗的完整流程:

数据获取与清洗流程 Yahoo Finance 东方财富 数据获取 缺失值处理 列名统一 日期对齐 统一格式的行情数据 可用于策略回测

说白了,数据获取就三步:选源 → 抓取 → 清洗。每一步都有坑,但踩过一次就记住了。

我的建议:刚开始别追求完美。先拿少量数据跑通流程,再逐步完善。数据清洗的代码,值得你花时间封装成函数,以后每个项目都能复用。

好了,这一章的内容就到这里。数据到手了,下一章咱们就可以开始做真正的跨品种套利分析了。


公众号:蓝海资料掘金营,微信deep3321