第三章:金融数据获取——Tushare/AkShare数据接口、股票/期货/加密货币数据获取、数据存储与缓存策略

做量化交易,第一道坎就是数据。我见过太多人策略写得漂亮,结果数据源没选对,回测跑出来全是幻觉。说白了,数据是量化系统的地基,地基不稳,楼盖得再高也得塌。

这一章,我带你搞定数据获取的全流程。从接口选择到存储策略,咱们一步到位。

3.1 数据接口选型:Tushare vs AkShare

国内量化圈,Tushare和AkShare是两大主流。我个人习惯两个都备着,哪个好用用哪个。但你要搞清楚它们的区别。

特性 Tushare Pro AkShare
数据源 自建数据库,稳定 爬取公开网站,实时
费用 积分制,部分免费 完全免费
速度 快,有缓存 依赖目标网站
覆盖范围 A股、基金、指数 A股、期货、加密货币、宏观
文档质量 清晰,有社区 更新快,但略乱

我在项目中遇到过一个问题:用AkShare拉期货数据,某天突然报错,原来是交易所网站改版了。所以我的建议是——关键数据用Tushare,辅助数据用AkShare,两者互补。

我的小技巧: 注册Tushare后,先攒积分。每天签到、分享都能加分。攒到2000分,基本够用。

3.2 股票数据获取实战

先看Tushare怎么拿A股日线数据。代码很简单,但有几个坑要注意。

import tushare as ts

# 初始化,token在官网注册获取
pro = ts.pro_api('你的token')

# 获取平安银行日线数据
df = pro.daily(ts_code='000001.SZ', start_date='20240101', end_date='20240301')
print(df.head())

嗯,这里要注意:ts_code的格式是「代码.交易所」,上交所是.SH,深交所是.SZ。我刚开始写的时候,老把.SH写成.SH,结果数据死活拉不出来。

再看AkShare的写法,更直接一些:

import akshare as ak

# 获取A股日线
df = ak.stock_zh_a_hist(symbol="000001", period="daily", 
                        start_date="20240101", end_date="20240301", adjust="qfq")
print(df.head())

AkShare默认返回前复权数据,这个很实用。你想想看,做回测如果不复权,分红送股直接让你的策略曲线失真。

避坑指南: 我曾经因为没复权,回测一个分红多的股票,收益率虚高20%。后来查了半天才发现是数据问题。所以,做回测一定要用复权数据

3.3 期货数据获取

期货数据和股票不太一样。它有主力合约、连续合约的概念。直接拉单个合约,你会发现数据断断续续的。

我的做法是拉「主力连续」合约。AkShare里这样搞:

import akshare as ak

# 获取螺纹钢主力连续
df = ak.futures_main_sina(symbol="RB0")
print(df.tail())

这里RB0就是螺纹钢主力连续。数字0代表当前主力,1代表下一个主力。Tushare也有类似功能,用fut_mapping接口。

为什么强调主力连续?因为期货合约会到期,你不可能一直交易同一个合约。主力连续帮你自动切换,省心很多。

核心要点: 期货数据一定要处理「换月跳空」。主力切换时会有价格跳空,直接回测会失真。我一般用「复权」或「价差调整」来处理。

3.4 加密货币数据获取

加密货币这块,AkShare直接支持。但说实话,它的数据源是公开的,延迟比较大。做实时交易的话,建议用交易所API。

import akshare as ak

# 获取比特币现货数据
df = ak.cryptocurrency_hist(symbol="BTC", period="daily")
print(df.head())

这里拿的是Binance的数据。如果你需要分钟级数据,可以加period="1min"。不过要注意,加密货币是7×24小时交易,数据量巨大。我建议只拉最近30天的,别贪多。

我个人习惯把加密货币数据单独存一个库。因为它的结构和A股差异太大——没有涨跌停、没有休市、交易时间不连续。

3.5 数据存储策略

数据拉下来,存哪?我踩过不少坑。最开始用CSV,后来用SQLite,现在用InfluxDB。给你看看我的选择逻辑:

存储方式 适用场景 缺点
CSV 小数据量、快速验证 查询慢、无索引
SQLite 单机、百万级数据 并发差
MySQL/PostgreSQL 团队协作、千万级 部署麻烦
InfluxDB 时序数据、高频 学习成本高

我的建议是:个人用SQLite就够了。代码简单,不用装数据库。团队用PostgreSQL,支持窗口函数,做因子分析很方便。

import sqlite3
import pandas as pd

# 创建数据库
conn = sqlite3.connect('quant_data.db')

# 存储DataFrame
df.to_sql('stock_daily', conn, if_exists='append', index=False)

# 读取数据
df = pd.read_sql("SELECT * FROM stock_daily WHERE ts_code='000001.SZ'", conn)
我的习惯: 每天收盘后跑一次增量更新,只拉当天的数据。全量拉取太慢了,而且容易触发接口限流。

3.6 缓存策略:别让接口累死

你想想看,每次回测都去拉数据,接口不封你才怪。缓存是必须的。

我的缓存策略分三层:

  1. 内存缓存:用Python的lru_cache,同一个交易日的数据只拉一次。
  2. 文件缓存:用Parquet格式存本地,比CSV快10倍。
  3. 数据库缓存:存到SQLite,方便跨进程共享。

代码实现很简单:

from functools import lru_cache
import pandas as pd

@lru_cache(maxsize=128)
def get_stock_data(ts_code, start_date, end_date):
    # 先查数据库,没有再拉接口
    df = pd.read_sql(...)
    if df.empty:
        df = pro.daily(ts_code=ts_code, start_date=start_date, end_date=end_date)
        df.to_sql('stock_daily', conn, if_exists='append')
    return df

这里有个细节:lru_cache的参数必须是可哈希的。所以日期要转成字符串,别传datetime对象。

注意: 缓存一定要设置过期时间。比如日线数据,当天收盘后缓存就失效了。我一般用time.time()加个判断,超过当天15:30就重新拉。

3.7 知识体系总览

这一章的内容比较多,我画了张图帮你理清思路:

金融数据获取知识体系 数据源层 Tushare Pro AkShare 交易所API 数据获取层 股票数据 期货数据 加密货币 存储与缓存层 SQLite/MySQL Parquet缓存 内存缓存

这张图把整个数据流程串起来了。从上到下,数据源→获取→存储,每一步都有讲究。你照着这个框架搭,基本不会出大问题。

最后说一句:数据获取是脏活累活,但也是最有价值的活。把这一步做扎实了,后面的策略开发就是水到渠成的事。


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