数据获取与存储:从零开始搭建你的金融数据仓库
做金融时间序列分析,第一步就是搞到数据。这事听起来简单,但坑不少。
我刚开始做量化研究时,花了一周时间手动下载股票数据,结果发现日期对不上、复权方式搞错了……后来我学乖了,直接用现成的库来获取数据。今天咱们就聊聊怎么用 yfinance 和 pandas-datareader 拿数据,以及存成什么格式最靠谱。
核心观点:数据获取不是简单的"下载",而是要考虑数据源可靠性、频率对齐、存储效率三个维度。选错了存储格式,后面分析时你会想哭的。
2.1 用 yfinance 获取股票数据
yfinance 是我个人最常用的股票数据源。它从 Yahoo Finance 拉数据,覆盖全球主要市场,而且免费。
安装很简单:
pip install yfinance
获取单只股票的历史数据:
import yfinance as yf
# 获取贵州茅台(A股代码:600519.SS)
maotai = yf.download('600519.SS', start='2020-01-01', end='2023-12-31')
print(maotai.head())
这里有个坑——A股代码后面要加后缀。上海交易所加 .SS,深圳交易所加 .SZ。我一开始不知道,查了半天数据都是空的,后来才发现是代码格式问题。
获取多只股票也很方便:
# 获取多只股票
tickers = ['600519.SS', '000001.SZ', 'AAPL', 'TSLA']
data = yf.download(tickers, start='2020-01-01', end='2023-12-31')
# 默认返回多重索引的DataFrame
close_prices = data['Close'] # 只取收盘价
小技巧:如果你只需要收盘价,可以设置 auto_adjust=True,这样返回的数据会自动进行复权调整,省去手动计算的麻烦。
2.2 用 pandas-datareader 获取经济数据
股票数据只是金融分析的一部分。宏观经济数据同样重要,比如 GDP、CPI、利率等。这时候 pandas-datareader 就派上用场了。
它支持多个数据源:FRED(美联储经济数据库)、World Bank、OECD 等。
import pandas_datareader.data as web
import datetime
# 从FRED获取美国CPI数据
start = datetime.datetime(2010, 1, 1)
end = datetime.datetime(2023, 12, 31)
cpi = web.DataReader('CPIAUCSL', 'fred', start, end)
print(cpi.head())
FRED 的数据代码需要去官网查。比如 GDP 是 GDPC1,失业率是 UNRATE。我建议你建一个代码映射表,方便以后复用。
获取中国宏观经济数据呢?嗯,这个有点麻烦。FRED 里中国数据不全,我一般用 akshare 或者直接爬取国家统计局网站。不过那是另一个话题了。
2.3 数据存储格式:CSV、Parquet、HDF5
数据拿到手了,存哪里?你可能会想:"存 CSV 不就行了?" 嗯,小数据量没问题,但一旦数据量大了,CSV 的缺点就暴露了。
| 格式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| CSV | 通用、可读性强、Excel能打开 | 占用空间大、读写慢、不支持数据类型 | 小数据集、数据交换 |
| Parquet | 列式存储、压缩率高、读写快 | 二进制格式、不易直接查看 | 大数据集、分析场景 |
| HDF5 | 支持复杂数据结构、快速I/O | 学习曲线陡、文件易损坏 | 科学计算、高频数据 |
我个人习惯:日常分析用 Parquet,长期归档用 HDF5。CSV 只用来做数据交换,比如给同事发数据。
看看代码怎么写:
# CSV
df.to_csv('stock_data.csv', index=False)
# Parquet(需要安装 pyarrow 或 fastparquet)
df.to_parquet('stock_data.parquet', index=False)
# HDF5
df.to_hdf('stock_data.h5', key='stock', mode='w')
注意:HDF5 写入时一定要指定 key 参数,否则会报错。而且 HDF5 文件在写入过程中如果程序崩溃,整个文件可能损坏。我吃过这个亏,后来改用 Parquet 了。
2.4 数据库存储:SQLite 与 InfluxDB
当数据量达到百万级别,文件存储就不够用了。这时候需要上数据库。
SQLite:轻量级关系型数据库
SQLite 不需要单独安装服务器,数据存在一个文件里,特别适合单机分析。
import sqlite3
import pandas as pd
# 创建数据库连接
conn = sqlite3.connect('finance.db')
# 将DataFrame写入数据库
df.to_sql('stock_prices', conn, if_exists='replace', index=False)
# 从数据库读取
query = "SELECT * FROM stock_prices WHERE Date > '2023-01-01'"
result = pd.read_sql(query, conn)
conn.close()
SQLite 的优点是简单,缺点是并发写入性能差。如果你只是一个人做研究,完全够用。
InfluxDB:专为时间序列设计
InfluxDB 是专门为时间序列数据设计的数据库。它的查询语法和 SQL 类似,但针对时间范围查询做了优化。
from influxdb import InfluxDBClient
# 连接InfluxDB
client = InfluxDBClient(host='localhost', port=8086)
client.create_database('finance')
# 写入数据
json_body = [
{
"measurement": "stock_price",
"tags": {"ticker": "600519.SS"},
"time": "2023-01-01T00:00:00Z",
"fields": {"close": 2050.0, "volume": 1000000}
}
]
client.write_points(json_body)
# 查询数据
results = client.query("SELECT * FROM stock_price WHERE time > '2023-01-01T00:00:00Z'")
我的建议:如果你处理的是高频数据(比如分钟级、秒级),InfluxDB 是首选。它的压缩率和查询速度比 SQLite 好太多。但如果是日频数据,SQLite 完全够用,没必要引入额外组件。
2.5 本章知识体系
下面这张图帮你理清数据获取与存储的整体脉络:
这张图展示了数据从获取到存储再到应用的完整链路。你可以看到,数据源层负责从不同渠道拉取数据,存储层根据数据量和用途选择合适的格式或数据库,最后应用层进行清洗、分析和建模。
实际项目中,我通常这样搭配:用 yfinance 拉股票数据存 Parquet,用 pandas-datareader 拉经济数据存 SQLite。这样既保证了分析效率,又方便后续查询。
一句话总结:数据获取要选对工具,数据存储要选对格式。别让数据获取成为你分析的瓶颈。