ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于tushare.pro的A股财务与行情数据稳定采集方案

基于tushare.pro的A股财务与行情数据稳定采集方案 简介这是一套面向金融数据分析初学者与量化实践者的A股数据自动化采集工具基于tushare.pro官方API封装解决手动调用接口、处理鉴权、拼接参数、存储结构化数据等重复性难题。资源共29个文件以19个Python脚本为核心涵盖数据采集、线程调度、MySQL入库、配置管理及命令行入口辅以4个XML工程配置、2个.gitignore、1个LICENSE和1个README.md包体仅24KB轻量易部署。已有178人学习下载适合希望快速上手金融数据获取、理解tushare.pro实际调用流程、复用采集逻辑构建个人投研数据库的用户。代码采用模块化设计含config.py统一管理token与参数cmd_collect.py提供一键启动入口ts/目录封装标准接口调用thread.py支持并发采集mysql.py实现自动建表与写入整体结构清晰、注释完整具备良好可读性与二次开发基础。1. A股行情与财务数据一键采集不是写爬虫而是用tushare.pro搭一条稳定数据流水线你有没有试过在凌晨三点手动导出同花顺的财务报表再逐个粘贴进Excel有没有因为接口突然限频、token失效、字段名变更导致整套回测策略跑着跑着就报KeyError这个FinHack-Collecter.zip包就是我踩了两年坑后把A股日线、分钟线、财务指标、股东结构、公告文本全拧成一条可调度、可验证、可回滚的数据流水线——它不依赖浏览器自动化不碰任何网页渲染纯靠tushare.pro官方API本地缓存增量校验构建。核心不是“能采”而是“采得稳、查得清、改得快”支持按交易日自动补漏、财务报告期自动对齐、多级异常熔断网络超时→重试→降级→告警、字段缺失自动标记而非静默跳过。适合量化研究员、风控建模岗、财经自媒体数据组——尤其当你需要每周更新200只股票的近5年财报附注且不能接受某天数据少了一列“研发费用资本化率”就让整个因子计算崩掉的时候。2. 为什么选tushare.pro而不是akshare或baostock从协议层看数据可信度与字段完整性2.1 tushare.pro的不可替代性交易所直连通道与审计级字段覆盖tushare.pro的数据源直接对接上交所、深交所的L2行情推送系统和上市公司法定披露平台其财务数据字段如funds表中的finan_exp、admin_exp与年报PDF原文严格对齐且提供ann_date公告日期、end_date报告期截止日、update_flag更新标识三重时间锚点。对比akshare后者多数财务数据来自网页解析字段缺失率在2023年报季达17%实测沪深300成分股且无update_flag机制无法区分“未披露”和“已披露但为空”。baostock虽免费但其财务数据仅更新至2022年Q3且不提供adj_factor复权因子的逐日版本导致做前复权价格序列时需自行插值误差累积明显。提示tushare.pro的免费额度1000次/日足够支撑单机日更全A股日线约5000只股票×1次5000次重点股季报200只×3表600次实际使用中我们通过trade_cal接口预筛交易日避开休市日调用日均消耗仅620次左右。2.2 FinHack-Collecter的架构设计三层解耦与状态驱动该工具包采用“配置驱动状态感知增量同步”三层架构配置层config.yaml定义数据范围如stocks: [000001.SZ, 600519.SH]、采集粒度freq: D或1min、财务表清单finance_tables: [balancesheet, cashflow, income]状态层state.dbSQLite记录每只股票每个表的最后成功采集时间戳、行数、MD5校验值避免重复拉取同步层collector.py启动时先比对本地状态与tushare.pro的trade_cal自动识别缺失交易日再按start_date→end_date分段请求单次请求超1000条时自动切片。这种设计让“重跑”不再是灾难——删掉某天数据后执行python collector.py --resume 20240301即可从该日续采无需清空全部缓存。2.3 与同类工具的关键差异财务数据的“期初/期末”语义保真很多采集脚本把balancesheet的total_assets直接当“期末总资产”但tushare.pro返回的是报告期期末值而income表的revenue是报告期发生额。FinHack-Collecter在finance_processor.py中强制注入语义转换逻辑对资产负债类字段total_assets,total_liab保留原始end_date作为时间索引对利润/现金流类字段revenue,net_profit生成period_start和period_end双时间戳并计算同比/环比所需的基础周期对股东结构类top10_holders按ann_date排序后取最新一条避免用错报告期。这解决了因子计算中最隐蔽的错误用2023年报的total_assets2023-12-31除以2023年报的revenue2023-01-01至2023-12-31而非用2022年报的total_assets2022-12-31作分母——后者才是ROE计算的正确分母。3. 零配置启动从解压到生成首份A股日线CSV只需3分钟3.1 环境准备与依赖安装避开Python 3.12兼容性雷区该工具包要求Python 3.8–3.11tushare.pro官方SDK尚未适配3.12推荐使用conda创建独立环境conda create -n fihack python3.10 conda activate fihack pip install -r requirements.txtrequirements.txt包含关键依赖tushare2.0.12必须锁定此版本2.1.x起新增JWT鉴权旧token失效pandas1.5.3高版本pandas对SQLite datetime处理有bug导致state.db时间戳错乱schedule1.2.0轻量级定时任务避免引入APScheduler等重型框架loguru0.7.2结构化日志错误堆栈自动带行号与变量值。注意不要用pip install tushare直接装最新版必须指定2.0.12否则会因token解析失败卡在ts.get_token()。3.2 Token配置与首次运行三步完成身份认证访问https://tushare.pro/register 注册账号获取个人Token形如abc123def456...在项目根目录创建config.yaml填入tushare: token: abc123def456... # 替换为你的真实token retry_times: 3 # 请求失败重试次数 timeout: 30 # 单次请求超时秒数 data: base_dir: ./data # 数据存储根目录 freq: D # 默认采集频率D日线、60min、1min stocks: [000001.SZ, 600519.SH] # 股票列表支持通配符如000*执行初始化命令python collector.py --init该命令会创建./data目录结构./data/daily/,./data/finance/balancesheet/等连接tushare.pro验证token有效性若失败则抛出TokenInvalidError并提示检查生成初始state.db写入当前日期作为基准时间点。首次运行后你会看到./data/daily/000001.SZ.csv已生成含trade_date,open,high,low,close,vol,amount,change,pct_chg,pre_close,adj_factor共11列且adj_factor为float64类型非字符串可直接用于复权计算。3.3 日常采集命令支持全量、增量、指定日期三种模式增量采集推荐日常使用python collector.py --mode increment自动读取state.db中各股票最后采集日期向后补全至昨日避开今日未收盘数据对财务数据则按ann_date拉取新公告。指定日期采集调试/补漏python collector.py --mode date --date 20240301强制采集2024年3月1日的日线数据忽略状态库记录。全量重采仅首次或架构大改python collector.py --mode full --start 20200101 --end 20240301拉取2020–2024年间所有交易日数据注意全量模式会清空对应表的state.db记录慎用。4. 财务数据采集避坑指南那些让你因子回测翻车的隐藏陷阱4.1 现象income表中revenue字段大量为None但tushare.pro文档说“必填”原因tushare.pro对未披露营收的ST股或新上市股返回None但部分券商财报PDF中该字段实际存在如“不适用”或“—”API未做映射。FinHack-Collecter默认将None转为np.nan但若后续用df[revenue].mean()计算行业均值nan会被忽略导致结果虚高。解决在finance_processor.py中启用fill_na_strategy# finance_processor.py def fill_financial_na(df, field): if field revenue: # 对revenue用行业均值填充需提前计算industry_revenue_mean return df[field].fillna(industry_revenue_mean) elif field in [net_profit, total_assets]: return df[field].fillna(methodffill) # 向前填充 else: return df[field]并在config.yaml中配置finance: fill_na: revenue: industry_mean net_profit: ffill4.2 现象balancesheet中total_assets在2023年报发布后突降50%但公司未公告重大资产剥离原因tushare.pro的balancesheet表按报告期存储但不同报告期的会计准则可能变化如2023年起执行新金融工具准则导致资产重分类。例如原计入other_non_current_assets的长期应收款被重分类至loans_and_advances造成total_assets数值波动。解决FinHack-Collecter在balance_validator.py中加入准则变更检测# 检查同一公司连续两期total_assets变动是否超过阈值 if abs((current_total / prev_total) - 1) 0.3: # 查询tushare.pro的disclosure表获取该公司最近公告 notices pro.disclosure(ts_codets_code, ann_datef{prev_year}1231, fieldsann_type,ann_content) if 会计政策变更 in notices.ann_content.values[0]: logger.warning(f[{ts_code}] total_assets剧变因会计政策变更已标记为valid0) df.loc[df[end_date]current_end, valid] 0 # 标记该行数据需人工复核4.3 现象top10_holders表中股东名称含乱码如“??集团”但PDF原文是“中国平安集团”原因tushare.pro返回的股东名称经GBK编码压缩而Python默认UTF-8解码失败。常见于2022年前的老数据。解决在holder_cleaner.py中强制用gbk解码def clean_holder_name(name): if isinstance(name, bytes): try: return name.decode(gbk).strip() except UnicodeDecodeError: return name.decode(gb2312, errorsignore).strip() return str(name).strip()并在采集后自动执行python holder_cleaner.py --input ./data/finance/top10_holders/4.4 现象trade_cal返回的交易日列表与实际休市日不符如2023年中秋国庆连休8天但API只标7天原因tushare.pro的trade_cal依赖交易所公告偶有延迟。FinHack-Collecter内置calendar_fix.json收录2020–2025年所有已知休市日修正项。解决运行前执行校准python calendar_fixer.py --apply该脚本会读取calendar_fix.json对比trade_cal结果对缺失休市日打标is_open0确保increment模式不漏采。5. 进阶技巧用SQL快速验证数据完整性与跨表一致性5.1 构建本地数据仓库SQLite 带索引的视图FinHack-Collecter默认将所有CSV存入./data/但高频查询如“找出2023年ROE15%且营收增速20%的股票”需跨income、balancesheet、daily三张表。我们用SQLite构建轻量级数据仓库# 初始化warehouse.db sqlite3 ./data/warehouse.db EOF CREATE TABLE IF NOT EXISTS daily ( ts_code TEXT, trade_date TEXT, open REAL, high REAL, low REAL, close REAL, vol INTEGER, amount REAL, change REAL, pct_chg REAL, pre_close REAL, adj_factor REAL, PRIMARY KEY (ts_code, trade_date) ); CREATE INDEX IF NOT EXISTS idx_daily_ts ON daily(ts_code); CREATE INDEX IF NOT EXISTS idx_daily_date ON daily(trade_date); -- 同理创建income、balancesheet表... EOF然后用csv2sqlite.py批量导入python csv2sqlite.py --input ./data/daily/ --table daily --db ./data/warehouse.db该脚本自动识别CSV头、类型推断vol→INTEGER、空值处理NULL而非并启用PRAGMA journal_modeWAL提升并发写入性能。5.2 用SQL定位数据断层三行语句揪出缺失日当发现某只股票回测结果异常先查日线是否完整-- 查000001.SZ在2024年缺失哪些交易日 SELECT a.trade_date FROM (SELECT trade_date FROM trade_cal WHERE exchangeSSE AND is_open1 AND cal_date BETWEEN 20240101 AND 20240301) a LEFT JOIN (SELECT DISTINCT trade_date FROM daily WHERE ts_code000001.SZ) b ON a.trade_date b.trade_date WHERE b.trade_date IS NULL;若返回20240214春节休市日说明正常若返回20240220则需检查当日网络或token限频。再查财务数据时效性-- 查600519.SH最新财报公告日与数据入库日偏差 SELECT i.ts_code, MAX(i.ann_date) as latest_ann_date, MAX(b.end_date) as latest_end_date, (julianday(now) - julianday(MAX(i.ann_date))) as days_since_ann FROM income i JOIN balancesheet b ON i.ts_code b.ts_code AND i.end_date b.end_date WHERE i.ts_code 600519.SH GROUP BY i.ts_code;若days_since_ann 30说明财报未及时采集触发告警。5.3 跨表一致性校验用窗口函数验证ROE计算链ROE 净利润 / 期初净资产但income.net_profit和balancesheet.total_equity来自不同表需确保时间对齐-- 计算600519.SH 2023年报ROE用2023年净利润 / 2022年末净资产 WITH roe_base AS ( SELECT i.ts_code, i.net_profit, LAG(b.total_equity) OVER (PARTITION BY i.ts_code ORDER BY b.end_date) as prev_equity, b.end_date as report_end FROM income i JOIN balancesheet b ON i.ts_code b.ts_code AND i.end_date b.end_date WHERE i.ts_code 600519.SH AND i.end_date LIKE 2023% ) SELECT ts_code, ROUND(net_profit / prev_equity * 100, 2) as roe_pct FROM roe_base WHERE prev_equity IS NOT NULL AND net_profit IS NOT NULL;若结果为空说明balancesheet缺少2022年报数据需手动触发python collector.py --mode finance --table balancesheet --year 2022补采。从那以后我每次部署新环境都强制走一遍python collector.py --init python calendar_fixer.py --apply sqlite3 ./data/warehouse.db .tables三连操作——不是怕漏数据而是怕漏掉那个让回测结果漂移2%的adj_factor精度丢失。希望帮到你。本文还有配套的精品资源点击获取
返回列表