尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

我用 Tushare + Codex,把本地股票数据库补上了前后复权行情(已开源)

发布时间:2026/9/27 18:25:11

资讯中心
01
ARTICLE

我用 Tushare + Codex,把本地股票数据库补上了前后复权行情(已开源)

我用 Tushare + Codex,把本地股票数据库补上了前后复权行情(已开源)
1. 本地股票数据库为什么总在复权行情上卡住如果你已经用 Tushare 把股票基础信息、交易日历、日线行情同步到了本地 Parquet大概率会遇到一个很尴尬的问题打开 K 线一看历史上有好几个莫名其妙的跳空缺口。这不是数据错了而是日线行情默认是不复权的。现金分红、送股、转增、配股这些公司行为都会让除权除息日的参考价发生跳变原始价格序列因此不再连续。不复权数据拿来做动量因子、历史收益率、回测结果很容易失真。举个最直观的例子某只股票昨天收盘 10 元今天除息 0.5 元除息后参考价变成 9.5 元。表面看跌了 5%但你同时拿到了 0.5 元现金分红这个跌幅并不是真实亏损。复权要解决的核心问题就是把公司行为造成的价格跳变消掉让历史价格在同一套口径下可比。这篇要交付的是一套可跟做的补全方案用 Tushare 作为数据源用 Codex 生成补全脚本把复权因子同步进本地数据库再在查询层合成前复权和后复权行情。适合已经有一套本地股票数据系统、想补齐复权能力的开发者。核心结论先放这里本地系统应该存原始行情加复权因子而不是提前把复权价格落盘因为前复权价格会随着最新交易日变化而整体重算。2. 前置准备Tushare token 与 TaoToken 接入配置动手之前先把两件事准备好Tushare 的 token以及一个能稳定调用 Codex 的接入配置。Tushare 的 token 在官网注册后就能拿到这里不展开注册流程重点说配置怎么放。我习惯把敏感配置和项目配置分开。项目根目录放一个config.toml骨架token 走环境变量注入避免提交到仓库。下面这份骨架可以直接复制# config.toml [data_source] provider tushare token_env TUSHARE_TOKEN # 从环境变量读取不写死 api_url http://api.tushare.pro [storage] root ./data format parquet partition_by [trade_date] [sync] calendar_table trade_cal daily_table daily adj_factor_table adj_factor start_date 20150101 incremental true [query] engine duckdb default_adj none # none / qfq / hfq环境变量这样设置Linux/macOS 下export TUSHARE_TOKEN你的_tushare_tokenWindows PowerShell$env:TUSHARE_TOKEN你的_tushare_token接下来是 Codex 的接入。我这边用 TaoToken 统一管理模型调用官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 。如果你要长期跑编码和 Agent 任务建议直接看 Coding Plan比按次调用更划算https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。先把 API Key 建好https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。Codex 侧的配置我放在~/.codex/config.toml关键是把 base_url 指向 TaoToken 的 API# ~/.codex/config.toml model gpt-5.5 model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY wire_api chat对应的环境变量export TAOTOKEN_API_KEY你在控制台创建的_key配置好之后Codex 就能读取项目里的config.toml和现有代码结构按你的项目规范生成补全脚本。这一步的意义在于复权因子的同步逻辑、查询层的合成逻辑都可以让 Codex 基于你已有的同步框架来补而不是从零重写一套架构。3. 可复制配置复权因子同步与查询层合成3.1 复权因子同步模块复权因子的同步逻辑和日线行情几乎一样直接沿用已有的 CLI 和增量框架。核心是调 Tushare 的adj_factor接口按交易日历逐日拉取落到本地 Parquet。下面是一个精简后的同步脚本骨架# sync/adj_factor.py import os import tushare as ts import pandas as pd from pathlib import Path TOKEN os.environ[TUSHARE_TOKEN] pro ts.pro_api(TOKEN) DATA_ROOT Path(./data/adj_factor) def sync_adj_factor(trade_date: str) - pd.DataFrame: 按交易日同步全市场复权因子 df pro.adj_factor(trade_datetrade_date) if df.empty: return df out_dir DATA_ROOT / ftrade_date{trade_date} out_dir.mkdir(parentsTrue, exist_okTrue) df.to_parquet(out_dir / part-0.parquet, indexFalse) return df def sync_range(start_date: str, end_date: str): cal pro.trade_cal( exchangeSSE, start_datestart_date, end_dateend_date, is_open1, ) for d in cal[cal_date]: df sync_adj_factor(d) print(f{d} - {len(df)} rows)全量同步大概跑一小时左右取决于你的网络和 Tushare 积分权限。跑完之后本地就多了一类基础数据复权因子。3.2 查询层合成前复权与后复权查询层用 DuckDB 读本地 Parquet。关键设计是接口命名尽量对标 Tushare这样迁移成本低后续让 Agent 接管也顺。合成逻辑就是前面推导的几条公式后复权价格 原始价格 × 后复权因子前复权因子 当天后复权因子 / 最新一天后复权因子前复权价格 原始价格 × 前复权因子用 DuckDB 写出来大概是这样-- 后复权 SELECT d.ts_code, d.trade_date, d.open * a.adj_factor AS open_hfq, d.close * a.adj_factor AS close_hfq FROM daily d JOIN adj_factor a ON d.ts_code a.ts_code AND d.trade_date a.trade_date; -- 前复权先取每只股票最新一天的因子 WITH latest AS ( SELECT ts_code, adj_factor AS latest_factor FROM adj_factor QUALIFY ROW_NUMBER() OVER ( PARTITION BY ts_code ORDER BY trade_date DESC ) 1 ) SELECT d.ts_code, d.trade_date, d.open * (a.adj_factor / l.latest_factor) AS open_qfq, d.close * (a.adj_factor / l.latest_factor) AS close_qfq FROM daily d JOIN adj_factor a ON d.ts_code a.ts_code AND d.trade_date a.trade_date JOIN latest l ON d.ts_code l.ts_code;查询接口对外暴露一个adj参数adjNone返回不复权adjqfq返回前复权adjhfq返回后复权。开高低收、昨收、涨跌额、涨跌幅这些字段都按对应口径处理。4. 验证请求字段校验与回填结果确认配置写完不算完得验证。我一般分两步走先校验复权因子本身对不对再校验合成出来的价格序列连不连续。第一步拿 Tushare 返回的复权因子和本地自己算的做对比。前面推导过一个结论Tushare 的adj_factor可以直接看作后复权累计因子。验证方式是取一只发生过除权除息的股票用pre_close / 昨日 close推导单次调整因子再累乘看能不能和 Tushare 的因子对上。对得上说明口径理解没错。第二步校验前复权价格的最新一天是否等于原始价格。这是前复权的定义决定的最新交易日不调整前复权因子为 1。用 DuckDB 跑一句SELECT ts_code, trade_date, close AS raw_close, close * (adj_factor / latest_factor) AS qfq_close FROM ( SELECT d.ts_code, d.trade_date, d.close, a.adj_factor, MAX(a.adj_factor) OVER (PARTITION BY d.ts_code) AS latest_factor FROM daily d JOIN adj_factor a ON d.ts_code a.ts_code AND d.trade_date a.trade_date ) t WHERE trade_date (SELECT MAX(trade_date) FROM daily) LIMIT 5;如果raw_close和qfq_close完全相等说明前复权合成正确。后复权则相反最早一天的价格应该和原始价格一致。第三步检查历史序列有没有残留跳空。取一只分红频繁的股票把前复权收盘价画出来除权日的缺口应该消失。这一步用 pandas 快速看一眼就行import duckdb con duckdb.connect() df con.execute( SELECT trade_date, close FROM read_parquet(./data/daily/**/*.parquet) WHERE ts_code 600519.SH ORDER BY trade_date ).df() # 计算日收益率检查是否有异常跳变 df[ret] df[close].pct_change() print(df[ret].abs().max())如果最大单日收益率还在合理范围内说明复权生效了。5. 本篇常见错排查报错一adj_factor接口返回空。大概率是 Tushare 积分权限不够或者传入的trade_date不是交易日。先用trade_cal确认当天是否开市再检查账号权限。报错二前复权最新一天价格和原始价格对不上。检查latest_factor是不是取的每只股票最新交易日的因子。如果用了全市场统一的MAX(adj_factor)就会错。必须按ts_code分组取最新。报错三DuckDB 读 Parquet 报 schema 不一致。增量同步时如果字段顺序变了Parquet 文件之间 schema 会对不上。解决办法是同步时固定列顺序或者查询时显式指定列名。报错四Codex 生成的脚本用了不存在的字段。Tushare 不同接口字段名不一样daily里有pre_closeadj_factor里只有ts_code、trade_date、adj_factor。让 Codex 生成前先把接口文档或 SDK 源码喂给它减少幻觉。报错五复权因子同步到一半中断。增量同步要记录已完成的交易日下次从断点继续。可以在config.toml里加一个last_sync_date字段或者用本地文件记录进度。报错六前复权历史价格每次同步后都变。这是正常现象因为最新交易日的因子变了整个历史序列会按新基准重算。这也是为什么我坚持存因子而不是存前复权价格——存价格的话每次都要全量覆盖历史数据。6. 后续怎么用从复权行情到 Agent 交互到这一步本地数据系统已经支持交易日历、股票基础信息、不复权日线、前复权日线、后复权日线五种查询口径查询接口尽量对标 Tushare。日线级别研究常用的数据底座基本完整了。如果你想让模型直接验证复权合成结果可以用模型对话快速跑一遍逻辑https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 。如果你要长期跑编码和 Agent 任务比如让 Codex 持续维护这套同步和查询逻辑Coding Plan 更合适https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。接入过程中遇到报错先查接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 再对照 API Keys 页面确认 key 状态https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。这套设计最值得保留的一点是同步层负责沉淀基础事实查询层负责按场景组合计算。原始行情是基础事实复权因子也是基础事实前复权和后复权只是查询层的输出口径。后面继续加指数、ETF、分钟线、因子数据思路可以保持一致系统不会越做越重。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。