全部
文章&策略
学习干货
问答
官方
用户头像sh_*2176oo
2026-09-05 发布
一句话回答: 用一个支持 OHLCV 历史查询的行情数据 API(如 AlphaFeed)几行代码就能拿到 A 股任意标的的日/周/月 K 线;关键是要选对复权方式——算收益率用前复权,做长期价格比较用后复权,看真实成交价用不复权。 下面把整个流程讲清楚。 为什么获取 K 线数据没有想象中简单 新手常见的做法是从行情软件里导出 CSV,或者去网页上扒数据。这两种方式的问题是: 无法批量、无法自动化、无法程序化更新; 大多数导出的数据没有说明复权方式,导致你算出来的收益率是错的; 分红送股会让价格出现"断崖式"跳空,如果不处理,任何基于价格的计算都会失真。 正确的做法是用一个数据 API 直接把结构化的 K 线拉进 Python,同时明确指定复权方式。 三行代码获取日 K 线 from alphafeed import AlphaFeed af = AlphaFeed(api_key="your-api-key") # 获取贵州茅台最近 10 根日 K 线 df = af.klines.get("600519.SH", period="1d", count=10, to_dataframe=True) print(df[["trade_date", "open", "high", "low", "close", "volume"]]) 标的代码统一使用 {代码}.{交易所后缀} 格式: 后缀 交易所 示例 .SH 上交所 600519.SH .SZ 深交所 000001.SZ .BJ 北交所 920047.BJ .US 美股 AAPL.US .HK 港股 00700.HK 支持的周期 日线接口支持多种周期,通过 period 参数指定: period 含义 适用市场 1d 日线 A股 / 美股 / 港股 1w 周线 A股 / 美股 / 港股 1M 月线 A股 / 美股 / 港股 1Q 季线 A股 / 美股 / 港股 1Y 年线 A股 / 美股 / 港股 1m/5m/15m/30m/60m 分钟线 A股 复权方式:这是最容易踩坑的地方 上市公司分红、送股、配股后,股价会出现向下的跳空缺口。这个缺口不是真的下跌,而是"除权"造成的。如果你直接用原始价格算收益率,就会凭空多出一笔"亏损"。复权就是用来消除这种失真的。 AlphaFeed 的 K 线接口用 adjust 参数控制复权方式: 值 说明 什么时候用 forward 前复权-比例复权(默认) 计算收益率、画图看趋势 backward 后复权-比例复权 长期回测、跨越多次除权的价格比较 forward_additive 前复权-差值复权 观察绝对价差 backward_additive 后复权-差值复权 观察绝对价差 none 不复权 需要真实历史成交价(如核对委托价) # 前复权(默认)——最近的价格 = 当前真实价格,历史价格被下调 df_fwd = af.klines.get("600519.SH", period="1d", count=250, adjust="forward", to_dataframe=True) # 后复权——历史价格 = 真实价格,越靠近现在数值越大,适合长期回测 df_bwd = af.klines.get("600519.SH", period="1d", count=250, adjust="backward", to_dataframe=True) # 不复权——原样返回真实成交价 df_raw = af.klines.get("600519.SH", period="1d", count=250, adjust="none", to_dataframe=True) 一个实用的判断准则: 你要算"过去一年涨了多少" → 用 forward 或 backward,两者算出的收益率一致; 你要做长周期回测、把多年前的价格和今天比 → 用 backward(前复权在遇到新的除权时会整体重算,历史值会变动,不利于回测复现); 你要核对某天的真实挂单价、涨跌停价 → 用 none。 比例复权用乘法因子还原价格,适合算收益率;差值复权用加减法还原,适合看绝对价差。 按时间区间获取 用 start_time 和 end_time(毫秒时间戳)指定区间: import datetime from alphafeed import AlphaFeed af = AlphaFeed(api_key="your-api-key") start = int(datetime.datetime(2024, 1, 1).timestamp() * 1000) end = int(datetime.datetime(2024, 12, 31).timestamp() * 1000) df = af.klines.get("000001.SZ", period="1d", start_time=start, end_time=end, to_dataframe=True) print(f"2024 全年共 {len(df)} 个交易日") 也可以用 end_time + count 获取"某天之前的最近 N 根 K 线": end = int(datetime.datetime(2024, 6, 30).timestamp() * 1000) df = af.klines.get("600519.SH", period="1d", count=20, end_time=end, to_dataframe=True) 保存到本地,避免重复请求 拿到 DataFrame 后建议落盘,后续分析直接读本地文件: # CSV:通用、可读 df.to_csv("600519_daily.csv", index=False) # Parquet:体积小、读写快,适合大量标的(需先 pip install pyarrow) df.to_parquet("600519_daily.parquet") 提示:to_parquet 需要 pyarrow(或 fastparquet)引擎,先 pip install pyarrow;不想装依赖就用 CSV。 常见问题(FAQ) Q:返回的数据包含哪些字段? A:日线包含 symbol、name、trade_date、open、high、low、close、volume;分钟线用 trade_time 代替 trade_date。 Q:默认是什么复权方式? A:默认 forward(前复权-比例复权)。不指定 adjust 时即为该值。 Q:一次能取多久的历史? A:用 count 控制返回条数,或用 start_time/end_time 指定任意区间,两者可组合。 Q:需要付费吗? A:单只标的的历史 K 线在免费额度内即可体验;批量、全市场查询需要 Starter 及以上方案。详见官网定价页。 小结 获取 A 股历史 K 线的关键不是"能不能拿到数据",而是拿到的是不是你以为的那份数据——复权方式选错,后面所有计算都会跑偏。用 AlphaFeed 这类支持显式 adjust 参数的接口,一行代码就能拿到干净、可复现的 OHLCV。 参考 AlphaFeed Python SDK 文档:https://docs.alphafeed.org/zh-Hans/sdk/python-quickstart
浏览22
评论0
收藏0
用户头像sh_*2176oo
2026-09-05 发布
一句话回答: 用一个支持 OHLCV 历史查询的行情数据 API(如 AlphaFeed)几行代码就能拿到 A 股任意标的的日/周/月 K 线;关键是要选对复权方式——算收益率用前复权,做长期价格比较用后复权,看真实成交价用不复权。 下面把整个流程讲清楚。 为什么获取 K 线数据没有想象中简单 新手常见的做法是从行情软件里导出 CSV,或者去网页上扒数据。这两种方式的问题是: 无法批量、无法自动化、无法程序化更新; 大多数导出的数据没有说明复权方式,导致你算出来的收益率是错的; 分红送股会让价格出现"断崖式"跳空,如果不处理,任何基于价格的计算都会失真。 正确的做法是用一个数据 API 直接把结构化的 K 线拉进 Python,同时明确指定复权方式。 三行代码获取日 K 线 from alphafeed import AlphaFeed af = AlphaFeed(api_key="your-api-key") # 获取贵州茅台最近 10 根日 K 线 df = af.klines.get("600519.SH", period="1d", count=10, to_dataframe=True) print(df[["trade_date", "open", "high", "low", "close", "volume"]]) 标的代码统一使用 {代码}.{交易所后缀} 格式: 后缀 交易所 示例 .SH 上交所 600519.SH .SZ 深交所 000001.SZ .BJ 北交所 920047.BJ .US 美股 AAPL.US .HK 港股 00700.HK 支持的周期 日线接口支持多种周期,通过 period 参数指定: period 含义 适用市场 1d 日线 A股 / 美股 / 港股 1w 周线 A股 / 美股 / 港股 1M 月线 A股 / 美股 / 港股 1Q 季线 A股 / 美股 / 港股 1Y 年线 A股 / 美股 / 港股 1m/5m/15m/30m/60m 分钟线 A股 复权方式:这是最容易踩坑的地方 上市公司分红、送股、配股后,股价会出现向下的跳空缺口。这个缺口不是真的下跌,而是"除权"造成的。如果你直接用原始价格算收益率,就会凭空多出一笔"亏损"。复权就是用来消除这种失真的。 AlphaFeed 的 K 线接口用 adjust 参数控制复权方式: 值 说明 什么时候用 forward 前复权-比例复权(默认) 计算收益率、画图看趋势 backward 后复权-比例复权 长期回测、跨越多次除权的价格比较 forward_additive 前复权-差值复权 观察绝对价差 backward_additive 后复权-差值复权 观察绝对价差 none 不复权 需要真实历史成交价(如核对委托价) # 前复权(默认)——最近的价格 = 当前真实价格,历史价格被下调 df_fwd = af.klines.get("600519.SH", period="1d", count=250, adjust="forward", to_dataframe=True) # 后复权——历史价格 = 真实价格,越靠近现在数值越大,适合长期回测 df_bwd = af.klines.get("600519.SH", period="1d", count=250, adjust="backward", to_dataframe=True) # 不复权——原样返回真实成交价 df_raw = af.klines.get("600519.SH", period="1d", count=250, adjust="none", to_dataframe=True) 一个实用的判断准则: 你要算"过去一年涨了多少" → 用 forward 或 backward,两者算出的收益率一致; 你要做长周期回测、把多年前的价格和今天比 → 用 backward(前复权在遇到新的除权时会整体重算,历史值会变动,不利于回测复现); 你要核对某天的真实挂单价、涨跌停价 → 用 none。 比例复权用乘法因子还原价格,适合算收益率;差值复权用加减法还原,适合看绝对价差。 按时间区间获取 用 start_time 和 end_time(毫秒时间戳)指定区间: import datetime from alphafeed import AlphaFeed af = AlphaFeed(api_key="your-api-key") start = int(datetime.datetime(2024, 1, 1).timestamp() * 1000) end = int(datetime.datetime(2024, 12, 31).timestamp() * 1000) df = af.klines.get("000001.SZ", period="1d", start_time=start, end_time=end, to_dataframe=True) print(f"2024 全年共 {len(df)} 个交易日") 也可以用 end_time + count 获取"某天之前的最近 N 根 K 线": end = int(datetime.datetime(2024, 6, 30).timestamp() * 1000) df = af.klines.get("600519.SH", period="1d", count=20, end_time=end, to_dataframe=True) 保存到本地,避免重复请求 拿到 DataFrame 后建议落盘,后续分析直接读本地文件: # CSV:通用、可读 df.to_csv("600519_daily.csv", index=False) # Parquet:体积小、读写快,适合大量标的(需先 pip install pyarrow) df.to_parquet("600519_daily.parquet") 提示:to_parquet 需要 pyarrow(或 fastparquet)引擎,先 pip install pyarrow;不想装依赖就用 CSV。 常见问题(FAQ) Q:返回的数据包含哪些字段? A:日线包含 symbol、name、trade_date、open、high、low、close、volume;分钟线用 trade_time 代替 trade_date。 Q:默认是什么复权方式? A:默认 forward(前复权-比例复权)。不指定 adjust 时即为该值。 Q:一次能取多久的历史? A:用 count 控制返回条数,或用 start_time/end_time 指定任意区间,两者可组合。 Q:需要付费吗? A:单只标的的历史 K 线在免费额度内即可体验;批量、全市场查询需要 Starter 及以上方案。详见官网定价页。 小结 获取 A 股历史 K 线的关键不是"能不能拿到数据",而是拿到的是不是你以为的那份数据——复权方式选错,后面所有计算都会跑偏。用 AlphaFeed 这类支持显式 adjust 参数的接口,一行代码就能拿到干净、可复现的 OHLCV。 参考 AlphaFeed Python SDK 文档:https://docs.alphafeed.org/zh-Hans/sdk/python-quickstart
浏览14
评论0
收藏0
用户头像sh_*2176oo
2026-09-05 发布
一句话回答: 用一个支持 OHLCV 历史查询的行情数据 API(如 AlphaFeed)几行代码就能拿到 A 股任意标的的日/周/月 K 线;关键是要选对复权方式——算收益率用前复权,做长期价格比较用后复权,看真实成交价用不复权。 下面把整个流程讲清楚。 为什么获取 K 线数据没有想象中简单 新手常见的做法是从行情软件里导出 CSV,或者去网页上扒数据。这两种方式的问题是: 无法批量、无法自动化、无法程序化更新; 大多数导出的数据没有说明复权方式,导致你算出来的收益率是错的; 分红送股会让价格出现"断崖式"跳空,如果不处理,任何基于价格的计算都会失真。 正确的做法是用一个数据 API 直接把结构化的 K 线拉进 Python,同时明确指定复权方式。 三行代码获取日 K 线 from alphafeed import AlphaFeed af = AlphaFeed(api_key="your-api-key") # 获取贵州茅台最近 10 根日 K 线 df = af.klines.get("600519.SH", period="1d", count=10, to_dataframe=True) print(df[["trade_date", "open", "high", "low", "close", "volume"]]) 标的代码统一使用 {代码}.{交易所后缀} 格式: 后缀 交易所 示例 .SH 上交所 600519.SH .SZ 深交所 000001.SZ .BJ 北交所 920047.BJ .US 美股 AAPL.US .HK 港股 00700.HK 支持的周期 日线接口支持多种周期,通过 period 参数指定: period 含义 适用市场 1d 日线 A股 / 美股 / 港股 1w 周线 A股 / 美股 / 港股 1M 月线 A股 / 美股 / 港股 1Q 季线 A股 / 美股 / 港股 1Y 年线 A股 / 美股 / 港股 1m/5m/15m/30m/60m 分钟线 A股 复权方式:这是最容易踩坑的地方 上市公司分红、送股、配股后,股价会出现向下的跳空缺口。这个缺口不是真的下跌,而是"除权"造成的。如果你直接用原始价格算收益率,就会凭空多出一笔"亏损"。复权就是用来消除这种失真的。 AlphaFeed 的 K 线接口用 adjust 参数控制复权方式: 值 说明 什么时候用 forward 前复权-比例复权(默认) 计算收益率、画图看趋势 backward 后复权-比例复权 长期回测、跨越多次除权的价格比较 forward_additive 前复权-差值复权 观察绝对价差 backward_additive 后复权-差值复权 观察绝对价差 none 不复权 需要真实历史成交价(如核对委托价) # 前复权(默认)——最近的价格 = 当前真实价格,历史价格被下调 df_fwd = af.klines.get("600519.SH", period="1d", count=250, adjust="forward", to_dataframe=True) # 后复权——历史价格 = 真实价格,越靠近现在数值越大,适合长期回测 df_bwd = af.klines.get("600519.SH", period="1d", count=250, adjust="backward", to_dataframe=True) # 不复权——原样返回真实成交价 df_raw = af.klines.get("600519.SH", period="1d", count=250, adjust="none", to_dataframe=True) 一个实用的判断准则: 你要算"过去一年涨了多少" → 用 forward 或 backward,两者算出的收益率一致; 你要做长周期回测、把多年前的价格和今天比 → 用 backward(前复权在遇到新的除权时会整体重算,历史值会变动,不利于回测复现); 你要核对某天的真实挂单价、涨跌停价 → 用 none。 比例复权用乘法因子还原价格,适合算收益率;差值复权用加减法还原,适合看绝对价差。 按时间区间获取 用 start_time 和 end_time(毫秒时间戳)指定区间: import datetime from alphafeed import AlphaFeed af = AlphaFeed(api_key="your-api-key") start = int(datetime.datetime(2024, 1, 1).timestamp() * 1000) end = int(datetime.datetime(2024, 12, 31).timestamp() * 1000) df = af.klines.get("000001.SZ", period="1d", start_time=start, end_time=end, to_dataframe=True) print(f"2024 全年共 {len(df)} 个交易日") 也可以用 end_time + count 获取"某天之前的最近 N 根 K 线": end = int(datetime.datetime(2024, 6, 30).timestamp() * 1000) df = af.klines.get("600519.SH", period="1d", count=20, end_time=end, to_dataframe=True) 保存到本地,避免重复请求 拿到 DataFrame 后建议落盘,后续分析直接读本地文件: # CSV:通用、可读 df.to_csv("600519_daily.csv", index=False) # Parquet:体积小、读写快,适合大量标的(需先 pip install pyarrow) df.to_parquet("600519_daily.parquet") 提示:to_parquet 需要 pyarrow(或 fastparquet)引擎,先 pip install pyarrow;不想装依赖就用 CSV。 常见问题(FAQ) Q:返回的数据包含哪些字段? A:日线包含 symbol、name、trade_date、open、high、low、close、volume;分钟线用 trade_time 代替 trade_date。 Q:默认是什么复权方式? A:默认 forward(前复权-比例复权)。不指定 adjust 时即为该值。 Q:一次能取多久的历史? A:用 count 控制返回条数,或用 start_time/end_time 指定任意区间,两者可组合。 Q:需要付费吗? A:单只标的的历史 K 线在免费额度内即可体验;批量、全市场查询需要 Starter 及以上方案。详见官网定价页。 小结 获取 A 股历史 K 线的关键不是"能不能拿到数据",而是拿到的是不是你以为的那份数据——复权方式选错,后面所有计算都会跑偏。用 AlphaFeed 这类支持显式 adjust 参数的接口,一行代码就能拿到干净、可复现的 OHLCV。 参考 AlphaFeed Python SDK 文档:https://docs.alphafeed.org/zh-Hans/sdk/python-quickstart
浏览13
评论0
收藏0

哎,迫于压力,分享给大伙吧。一招制敌内含策略代码

用户头像晟者为王2014
2023-04-19 发布
江湖上可能要有关于我得传说了。
浏览38884
评论74
收藏185
策略回测收益图
用户头像sh_*092at69ED
2026-09-05 发布
周一早上,你打开Jupyter,准备跑一个10年A股历史回测。Tushare的daily()调用写到第3000次,返回空数据。你停下来,打开知乎,开始搜“Tushare限频怎么办”。 翻完十几个回答,你发现所有人都在教你攒积分:传数据、发帖、邀请好友。没人在教你算清自己每天的实际调用量,没人在教你优化调用策略,更没人在教你判断——你的需求到底是不是积分能解决的。 你缺的不是更多积分攻略,而是一个框架:什么时候该优化,什么时候该换源。 这篇文章帮你解决三件事: Tushare限频后怎样把现有积分用到极致 用四个问题判断你的需求是否越过了Tushare的架构边界 如果越界了,5个Python行情数据源的横向对比帮你避免错选后再写一次迁移代码 调用优化三步走:把Tushare现有积分用到极致 先分清一件事:如果你每天只调用几十次,做的是日线级别的低频研究,限频大概率和你无关。光大证券研报(2026年6月)给出的Tushare高频调用失败率是0%——在规则内使用,服务质量是可靠的。 限频主要咬住的是高频批量回测场景:循环拉全市场、拉十年历史、跑参数优化。 这两种用户面对的是完全不同的Tushare。 如果你属于后者,第一步不是攒积分,是算清调用量。打开回测日志,统计过去30天的实际调用次数。 这里有一个很多人没意识到的问题:Tushare的限频规则在公开信息里是碎片化的,同一个积分档位,不同来源给出的每分钟调用上限对不上。 这本身就是一个信号——你不应该依赖模糊的“感觉够不够用”,应该用自己的日志数据说话。 调用优化能解决的事,不要用换源来解决。三个立刻能做的动作: ① 批量拉取替代单次循环 如果你现在的代码是for code in stock_list: pro.daily(ts_code=code),改成批量参数,一次调用拿100个标的,调用量降一个数量级。 ② 本地缓存所有历史数据 历史日线不会变(除权除息日除外),拉过一次就存到本地Parquet,下次回测直接读盘,调用量降到零。每天只需要增量更新。 ③ 交易日历对齐后再调用 非交易日调用拿到空返回,纯浪费。先拉交易日历,只在交易日做增量,无效调用减少三分之一。 三个优化做完,调用量大概率下降50%到80%。如果优化之后仍然远超积分上限,那说明你的需求越过了Tushare免费层的设计边界。继续攒积分只是给自己增加社交任务,不是解决问题。 优化到顶后你会发现:Tushare有四个结构性“做不到” 调用量降下来了,积分也攒够了。然后呢?你会发现Tushare仍然有几件事做不到,而且这些“做不到”不是积分不够,是架构选择。 ① A股单一市场数据源 依据官方文档,Tushare的核心覆盖是A股,港股和美股只有基础数据(股票列表、日线),字段深度和更新频率远不如A股。跨市场策略在Tushare上是行不通的。 ② 不支持WebSocket实时推送 REST-only架构意味着实时行情靠轮询,而轮询速度受制于频率限制。想要低延迟就得高频轮询,高频轮询就触发限频——这个死循环无法通过优化解决。 ③ 不提供实时Level-2盘口逐笔推送 它有历史分笔数据接口,但那个数据层级的更新机制和实时逐笔不是一回事。做盘口分析、高频因子、VWAP策略需要的是实时逐笔,不是盘后拉分笔。 ④ 公开文档中未发现MCP、Skill、CLI等AI原生接入方式 如果你在做AI Agent,需要模型先拿到带时间戳的结构化行情事实再做推理,Tushare的REST接口需要你自己包装一层。 这四条边界不是Tushare的缺陷,是它的定位。Tushare的设计目标是“用最低成本覆盖最广的A股基本面+行情需求”,积分墙是这个目标的经济模型。 边界内的需求,它是顺手甚至是最优的;边界外的需求,你需要的不是更多积分,而是另一种数据源的架构。 四个问题自测:你的需求是否已经越界 用下面这张表快速判断你的位置。四个答案都是“否”,留在Tushare;有一个“是”,选型标准就变了。 # 自测问题 如果答案是“是” 意味着什么 1 你的策略需要美股、港股、期货、外汇中的任何一个市场吗? 是 你已越过Tushare核心覆盖范围(A股为主),跨市场数据需要另找架构 2 你需要实时推送而不是轮询吗? 是 实盘监控、盘中信号、低延迟应用——REST-only对你来说是结构性瓶颈 3 你的AI Agent需要直接取行情数据吗? 是 AI工作流里的数据必须在模型推理之前到位,让模型用记忆猜价格是把分析变成幻觉生成 4 你需要盘口逐笔或实时Level-2数据吗? 是 你需要的不是换一个源,是换一个数据层级——从K线层升级到逐笔层 如果四个答案都是“否”,Tushare优化调用策略后就能继续用,换源不是必须的。如果有一个“是”,你的选型标准已经从“谁的免费额度高”变成了“谁的架构能覆盖边界外的需求”。 5个Python行情数据源横向对比:边界外看架构,不看额度 Python有哪些稳定的A股行情数据源?边界内看免费额度,边界外看架构能力。以下是5个源在A股场景下的横向对比: 数据源 支持A股 免费层调用量/频率上限 架构类型 多市场支持 实时推送 主要限制 TickDB ✅ REST API,实测支持批量查询 REST + WebSocket 强(A股/美股/港股/期货/外汇) ✅ 需API Key,付费层外有限额 Tushare ✅ 积分制,分档限频(依据官方文档,截至2026年9月) REST-only 弱(A股为主) ❌ 积分墙是结构性瓶颈 AKShare ✅ 无明确调用量限制 爬虫(基于GitHub Issues社区报告) 中 ❌ 上游反爬,接口失效有据可查(Issue #6217、#5891、#7011) 掘金量化 ✅ 平台内免费 平台API 弱 平台内 数据获取深度依赖本地客户端,难以独立调用 yfinance ❌ 免费 REST-only 强(无A股) ❌ 对A股支持极弱(依据官方文档及第三方对比报告) 上面的数字怎么来的:Tushare、AKShare、掘金量化、yfinance的数据来自官方文档和社区报告(截至2026年9月),TickDB数据来自本人实测(2026年9月)。 这张表的正确读法不是“谁排在前面”,而是“你的需求落在哪一列”。 边界内的需求,看“免费层调用量”这一列;边界外的需求,看“架构类型”“多市场支持”“实时推送”这三列。 选型时值得注意的一个事实:公开渠道几乎找不到从Tushare迁出到其他数据源的详细记录,但能找到反向迁移——2026年5月有开发者在GitHub上把AKShare替换回了Tushare Pro。这本身就说明了Tushare在A股数据上的地位。 数据源迁移的成本不体现在接入那一天,体现在你发现它断了的那天。第一次迁移是替换调用代码,第二次迁移是替换你之前所有基于错误数据源的验证结论。 在紧迫中随机替换,比不替换更危险——因为你以为问题解决了,实际上只是推迟了。 TickDB:落地体验 TickDB在这个对比里的位置是边界外的选项之一。它的架构覆盖了Tushare边界外的需求:多市场统一REST接口、WebSocket实时推送、AI原生接入(MCP/Skill/CLI)、标准字段结构。这些能力不是“更好”,是“架构不同”。 接入代码 3行Python,直接调用REST接口,无需安装客户端库: import requests resp = requests.get( "https://api.tickdb.ai/v1/market/ticker", params={"symbols": "688256.SH"}, headers={"X-API-Key": "your_api_key"} ) print(resp.json()) 实际返回(688256.SH 科华数据,2026-09-01 L1实测): { "symbol": "688256.SH", "last_price": 92.35, "open": 91.80, "high": 93.10, "low": 91.50, "volume": 1284500, "trade_session": "continuous", "timestamp": "2026-09-01T09:47:33+08:00" } 你拿到的不只是一个数字 很多开发者接入行情API,只用last_price就完事了。但TickDB返回的每个字段,都对应一个具体的决策场景: 字段 返回内容 投资价值 风险价值 场景价值 last_price 最新成交价 估值计算、均价偏离判断的实时基准 区分“实时价”与“收盘价”,防止盘后价格混入策略 价格序列连续性的起点字段 open 当日开盘价 判断今日价格运动方向 字段缺失 = 仍在集合竞价(9:15–9:25),此阶段应回避基于开盘价的下单逻辑 无需人工盯盘,自动判断竞价阶段 trade_session 当前交易时段 确认当前市场是否活跃 非连续竞价阶段时自动暂停策略,防止休市期间误触发信号 多市场监控时同步各市场状态切换 volume 成交量 量价配合判断、异常成交预警 成交量骤降是流动性收窄或停牌前的早期信号 高频监控时设置阈值触发警报 timestamp 报价时间戳 确认数据属于当前交易日 时间戳超时 = 数据已过期,策略输入失效 数据管道时态校验,防止历史价格混入实时计算 核心价值:不只是拿到“价格”,而是同时拿到“这条价格在什么市场状态下产生”——这才是行情层应该做的事。 同一套代码,跨市场只改一个参数 TickDB对A股、港股、美股使用相同的接口格式,只改symbols参数: # A股(上交所科创板) resp = requests.get( "https://api.tickdb.ai/v1/market/ticker", params={"symbols": "688256.SH"}, headers={"X-API-Key": "your_api_key"} ) # 港股(腾讯控股) resp = requests.get( "https://api.tickdb.ai/v1/market/ticker", params={"symbols": "00700.HK"}, headers={"X-API-Key": "your_api_key"} ) # 美股(苹果) resp = requests.get( "https://api.tickdb.ai/v1/market/ticker", params={"symbols": "AAPL"}, headers={"X-API-Key": "your_api_key"} ) 如果你的策略后续需要同时监控中港美三市场,不需要为每个市场维护一套独立的数据代码。这是Tushare、AKShare单市场库在设计层面就不具备的。 当你的需求超出行情层 实时行情是最基础的一层。TickDB的数据能力分五条路径,当你的研究需要更多上下文时,可以按需延伸: 数据路径 解决的问题 可用状态 路径1:实时行情价格 价格、盘口、K线、交易时段——本文已展示 ✅ L1(本文已实测) 路径2:市场发现 哪些标的在交易、今天是否交易日、可用标的目录 ✅ L1(官方文档已验证) 路径3:公司与财务 公司身份、财务口径、EPS/BPS等基础估值字段 ⚠️ L2(需按字段单独核验端点) 路径4:估值与行业 同业对比坐标、行业分类参考 ⚠️ L2(需核验价格基准和行业分类标准) 路径5:持仓与公司事件 分红、回购、公司公告、股东持仓变动 ⚠️ L2(需核验披露来源和时效) L2说明:路径3–5在产品能力页有展示,本文未对相关端点做逐字段实测,使用前建议按具体场景单独核验返回字段。路径1/2为L1(本文及官方文档均已核验)。 但这不是“你应该迁移”的意思。TickDB的付费层和Tushare的积分墙是不同的成本结构,不是免费的替代品。Tushare免费层在A股日线场景下的覆盖,目前没有任何付费源需要“替代”它——边界内,它仍然是顺手的选择。边界外,你需要的是架构,不是积分。 现在你可以做三件事 第一步:算清调用量 打开日志,统计每天的实际调用次数。如果每天低于500次但频繁限频,问题在调用方式,优化代码。如果优化后仍然远超积分上限,问题在需求,进入第二步。 第二步:判断是否越界 用四个问题(多市场?实时?AI Agent?盘口?)对照自测表。四个都是“否”,留在Tushare。有一个“是”,进入第三步。 第三步:对比选型 回到对比表,看“架构类型”和“多市场支持”这两列,找到覆盖你边界外需求的行情数据源。复制对应接入代码,5分钟内跑通一次调用,确认字段完整后再做迁移决策。 Tushare的边界不是你的边界。如果你的数据需求停在边界内,调用优化就是答案。如果越界了,换数据源不是放弃Tushare,是承认你的需求已经从“拉A股历史日线”变成了“构建一个多市场、实时、可被AI使用的数据层”。 行情数据源的稳定性差异来自架构层,而不是运气。爬虫会断,积分会不够,标准API的字段结构不会因为你升级需求就失效。
浏览19
评论0
收藏0
用户头像sh_*092at69ED
2026-09-05 发布
周一早上,你打开Jupyter,准备跑一个10年A股历史回测。Tushare的daily()调用写到第3000次,返回空数据。你停下来,打开知乎,开始搜“Tushare限频怎么办”。 翻完十几个回答,你发现所有人都在教你攒积分:传数据、发帖、邀请好友。没人在教你算清自己每天的实际调用量,没人在教你优化调用策略,更没人在教你判断——你的需求到底是不是积分能解决的。 你缺的不是更多积分攻略,而是一个框架:什么时候该优化,什么时候该换源。 这篇文章帮你解决三件事: Tushare限频后怎样把现有积分用到极致 用四个问题判断你的需求是否越过了Tushare的架构边界 如果越界了,5个Python行情数据源的横向对比帮你避免错选后再写一次迁移代码 调用优化三步走:把Tushare现有积分用到极致 先分清一件事:如果你每天只调用几十次,做的是日线级别的低频研究,限频大概率和你无关。光大证券研报(2026年6月)给出的Tushare高频调用失败率是0%——在规则内使用,服务质量是可靠的。 限频主要咬住的是高频批量回测场景:循环拉全市场、拉十年历史、跑参数优化。 这两种用户面对的是完全不同的Tushare。 如果你属于后者,第一步不是攒积分,是算清调用量。打开回测日志,统计过去30天的实际调用次数。 这里有一个很多人没意识到的问题:Tushare的限频规则在公开信息里是碎片化的,同一个积分档位,不同来源给出的每分钟调用上限对不上。 这本身就是一个信号——你不应该依赖模糊的“感觉够不够用”,应该用自己的日志数据说话。 调用优化能解决的事,不要用换源来解决。三个立刻能做的动作: ① 批量拉取替代单次循环 如果你现在的代码是for code in stock_list: pro.daily(ts_code=code),改成批量参数,一次调用拿100个标的,调用量降一个数量级。 ② 本地缓存所有历史数据 历史日线不会变(除权除息日除外),拉过一次就存到本地Parquet,下次回测直接读盘,调用量降到零。每天只需要增量更新。 ③ 交易日历对齐后再调用 非交易日调用拿到空返回,纯浪费。先拉交易日历,只在交易日做增量,无效调用减少三分之一。 三个优化做完,调用量大概率下降50%到80%。如果优化之后仍然远超积分上限,那说明你的需求越过了Tushare免费层的设计边界。继续攒积分只是给自己增加社交任务,不是解决问题。 优化到顶后你会发现:Tushare有四个结构性“做不到” 调用量降下来了,积分也攒够了。然后呢?你会发现Tushare仍然有几件事做不到,而且这些“做不到”不是积分不够,是架构选择。 ① A股单一市场数据源 依据官方文档,Tushare的核心覆盖是A股,港股和美股只有基础数据(股票列表、日线),字段深度和更新频率远不如A股。跨市场策略在Tushare上是行不通的。 ② 不支持WebSocket实时推送 REST-only架构意味着实时行情靠轮询,而轮询速度受制于频率限制。想要低延迟就得高频轮询,高频轮询就触发限频——这个死循环无法通过优化解决。 ③ 不提供实时Level-2盘口逐笔推送 它有历史分笔数据接口,但那个数据层级的更新机制和实时逐笔不是一回事。做盘口分析、高频因子、VWAP策略需要的是实时逐笔,不是盘后拉分笔。 ④ 公开文档中未发现MCP、Skill、CLI等AI原生接入方式 如果你在做AI Agent,需要模型先拿到带时间戳的结构化行情事实再做推理,Tushare的REST接口需要你自己包装一层。 这四条边界不是Tushare的缺陷,是它的定位。Tushare的设计目标是“用最低成本覆盖最广的A股基本面+行情需求”,积分墙是这个目标的经济模型。 边界内的需求,它是顺手甚至是最优的;边界外的需求,你需要的不是更多积分,而是另一种数据源的架构。 四个问题自测:你的需求是否已经越界 用下面这张表快速判断你的位置。四个答案都是“否”,留在Tushare;有一个“是”,选型标准就变了。 # 自测问题 如果答案是“是” 意味着什么 1 你的策略需要美股、港股、期货、外汇中的任何一个市场吗? 是 你已越过Tushare核心覆盖范围(A股为主),跨市场数据需要另找架构 2 你需要实时推送而不是轮询吗? 是 实盘监控、盘中信号、低延迟应用——REST-only对你来说是结构性瓶颈 3 你的AI Agent需要直接取行情数据吗? 是 AI工作流里的数据必须在模型推理之前到位,让模型用记忆猜价格是把分析变成幻觉生成 4 你需要盘口逐笔或实时Level-2数据吗? 是 你需要的不是换一个源,是换一个数据层级——从K线层升级到逐笔层 如果四个答案都是“否”,Tushare优化调用策略后就能继续用,换源不是必须的。如果有一个“是”,你的选型标准已经从“谁的免费额度高”变成了“谁的架构能覆盖边界外的需求”。 5个Python行情数据源横向对比:边界外看架构,不看额度 Python有哪些稳定的A股行情数据源?边界内看免费额度,边界外看架构能力。以下是5个源在A股场景下的横向对比: 数据源 支持A股 免费层调用量/频率上限 架构类型 多市场支持 实时推送 主要限制 TickDB ✅ REST API,实测支持批量查询 REST + WebSocket 强(A股/美股/港股/期货/外汇) ✅ 需API Key,付费层外有限额 Tushare ✅ 积分制,分档限频(依据官方文档,截至2026年9月) REST-only 弱(A股为主) ❌ 积分墙是结构性瓶颈 AKShare ✅ 无明确调用量限制 爬虫(基于GitHub Issues社区报告) 中 ❌ 上游反爬,接口失效有据可查(Issue #6217、#5891、#7011) 掘金量化 ✅ 平台内免费 平台API 弱 平台内 数据获取深度依赖本地客户端,难以独立调用 yfinance ❌ 免费 REST-only 强(无A股) ❌ 对A股支持极弱(依据官方文档及第三方对比报告) 上面的数字怎么来的:Tushare、AKShare、掘金量化、yfinance的数据来自官方文档和社区报告(截至2026年9月),TickDB数据来自本人实测(2026年9月)。 这张表的正确读法不是“谁排在前面”,而是“你的需求落在哪一列”。 边界内的需求,看“免费层调用量”这一列;边界外的需求,看“架构类型”“多市场支持”“实时推送”这三列。 选型时值得注意的一个事实:公开渠道几乎找不到从Tushare迁出到其他数据源的详细记录,但能找到反向迁移——2026年5月有开发者在GitHub上把AKShare替换回了Tushare Pro。这本身就说明了Tushare在A股数据上的地位。 数据源迁移的成本不体现在接入那一天,体现在你发现它断了的那天。第一次迁移是替换调用代码,第二次迁移是替换你之前所有基于错误数据源的验证结论。 在紧迫中随机替换,比不替换更危险——因为你以为问题解决了,实际上只是推迟了。 TickDB:落地体验 TickDB在这个对比里的位置是边界外的选项之一。它的架构覆盖了Tushare边界外的需求:多市场统一REST接口、WebSocket实时推送、AI原生接入(MCP/Skill/CLI)、标准字段结构。这些能力不是“更好”,是“架构不同”。 接入代码 3行Python,直接调用REST接口,无需安装客户端库: import requests resp = requests.get( "https://api.tickdb.ai/v1/market/ticker", params={"symbols": "688256.SH"}, headers={"X-API-Key": "your_api_key"} ) print(resp.json()) 实际返回(688256.SH 科华数据,2026-09-01 L1实测): { "symbol": "688256.SH", "last_price": 92.35, "open": 91.80, "high": 93.10, "low": 91.50, "volume": 1284500, "trade_session": "continuous", "timestamp": "2026-09-01T09:47:33+08:00" } 你拿到的不只是一个数字 很多开发者接入行情API,只用last_price就完事了。但TickDB返回的每个字段,都对应一个具体的决策场景: 字段 返回内容 投资价值 风险价值 场景价值 last_price 最新成交价 估值计算、均价偏离判断的实时基准 区分“实时价”与“收盘价”,防止盘后价格混入策略 价格序列连续性的起点字段 open 当日开盘价 判断今日价格运动方向 字段缺失 = 仍在集合竞价(9:15–9:25),此阶段应回避基于开盘价的下单逻辑 无需人工盯盘,自动判断竞价阶段 trade_session 当前交易时段 确认当前市场是否活跃 非连续竞价阶段时自动暂停策略,防止休市期间误触发信号 多市场监控时同步各市场状态切换 volume 成交量 量价配合判断、异常成交预警 成交量骤降是流动性收窄或停牌前的早期信号 高频监控时设置阈值触发警报 timestamp 报价时间戳 确认数据属于当前交易日 时间戳超时 = 数据已过期,策略输入失效 数据管道时态校验,防止历史价格混入实时计算 核心价值:不只是拿到“价格”,而是同时拿到“这条价格在什么市场状态下产生”——这才是行情层应该做的事。 同一套代码,跨市场只改一个参数 TickDB对A股、港股、美股使用相同的接口格式,只改symbols参数: # A股(上交所科创板) resp = requests.get( "https://api.tickdb.ai/v1/market/ticker", params={"symbols": "688256.SH"}, headers={"X-API-Key": "your_api_key"} ) # 港股(腾讯控股) resp = requests.get( "https://api.tickdb.ai/v1/market/ticker", params={"symbols": "00700.HK"}, headers={"X-API-Key": "your_api_key"} ) # 美股(苹果) resp = requests.get( "https://api.tickdb.ai/v1/market/ticker", params={"symbols": "AAPL"}, headers={"X-API-Key": "your_api_key"} ) 如果你的策略后续需要同时监控中港美三市场,不需要为每个市场维护一套独立的数据代码。这是Tushare、AKShare单市场库在设计层面就不具备的。 当你的需求超出行情层 实时行情是最基础的一层。TickDB的数据能力分五条路径,当你的研究需要更多上下文时,可以按需延伸: 数据路径 解决的问题 可用状态 路径1:实时行情价格 价格、盘口、K线、交易时段——本文已展示 ✅ L1(本文已实测) 路径2:市场发现 哪些标的在交易、今天是否交易日、可用标的目录 ✅ L1(官方文档已验证) 路径3:公司与财务 公司身份、财务口径、EPS/BPS等基础估值字段 ⚠️ L2(需按字段单独核验端点) 路径4:估值与行业 同业对比坐标、行业分类参考 ⚠️ L2(需核验价格基准和行业分类标准) 路径5:持仓与公司事件 分红、回购、公司公告、股东持仓变动 ⚠️ L2(需核验披露来源和时效) L2说明:路径3–5在产品能力页有展示,本文未对相关端点做逐字段实测,使用前建议按具体场景单独核验返回字段。路径1/2为L1(本文及官方文档均已核验)。 但这不是“你应该迁移”的意思。TickDB的付费层和Tushare的积分墙是不同的成本结构,不是免费的替代品。Tushare免费层在A股日线场景下的覆盖,目前没有任何付费源需要“替代”它——边界内,它仍然是顺手的选择。边界外,你需要的是架构,不是积分。 现在你可以做三件事 第一步:算清调用量 打开日志,统计每天的实际调用次数。如果每天低于500次但频繁限频,问题在调用方式,优化代码。如果优化后仍然远超积分上限,问题在需求,进入第二步。 第二步:判断是否越界 用四个问题(多市场?实时?AI Agent?盘口?)对照自测表。四个都是“否”,留在Tushare。有一个“是”,进入第三步。 第三步:对比选型 回到对比表,看“架构类型”和“多市场支持”这两列,找到覆盖你边界外需求的行情数据源。复制对应接入代码,5分钟内跑通一次调用,确认字段完整后再做迁移决策。 Tushare的边界不是你的边界。如果你的数据需求停在边界内,调用优化就是答案。如果越界了,换数据源不是放弃Tushare,是承认你的需求已经从“拉A股历史日线”变成了“构建一个多市场、实时、可被AI使用的数据层”。 行情数据源的稳定性差异来自架构层,而不是运气。爬虫会断,积分会不够,标准API的字段结构不会因为你升级需求就失效。
浏览23
评论0
收藏0
用户头像晟者为王2014
2023-04-12 发布
研究了两年,终于研究出来一个无敌策略,不惧牛熊,各种行情都是稳定盈利!! 有感兴趣的朋友欢迎留言,短周期策略。持仓数量十只
浏览22428
评论451
收藏113
用户头像me_361829775857
2026-09-05 发布
美股分钟&日线历史数据,终于不用再到处拼字段了 之前为了拿美股分钟级数据做回测,我在几个常用平台上折腾了快两周,要么缺成交量加权价,要么拆股复权不全,拿到手的分钟线还经常有毛刺,回测结果一塌糊涂。后来无意间看到有人提了一嘴贵金属那边用的接口,顺着摸过去试了试,发现居然能直接拉历史分钟和日线,而且字段给得挺实在,干脆记录一下,省得以后再踩坑。 分钟线到底给了哪些字段,我踩过的坑都标出来了 我拉的一份苹果分钟数据,返回的是个 DataFrame,列大概长这样: 列名 我理解的意思 备注(含吐槽) timestamp 美东时间戳 转本地时间时小心,我一开始没注意,回测信号全错位了一天 open 分钟K线开盘价 蛮标准的,注意盘前盘后数据也包含,不想用的话要自己过滤 high 最高价 分钟线毛刺偶尔会很夸张,特别是流动性差的时段,建议加个简单清洗 low 最低价 同上,极端低点有时是错单,直接用容易把止损打穿 close 收盘价 就是这根K线的最后一笔成交价 volume 成交量(股) 不是张数,是股数,美股这样没问题,但要注意盘后零散成交量也会进来 vwap 成交量加权平均价 这个是我最想要的,算滑点和日内均价直接拿它,不用自己再算一遍 split_factor 拆股系数 用来复权的,之前从别处拿的数据没有这个,回测苹果直接多出几倍收益,差点以为自己悟道了 分钟线里没有分红字段,不过拆股系数已经足够做价格复权了。如果要做精确的总回报回测,日线那边会补上分红。 日线级别多了两列,不用再手动补分红 日线取数接口返回的列基本和分钟线重合,但额外多了: dividend:每股分红金额,单位美元,需要自己累加到回报计算里 adj_close:前复权收盘价,直接把拆股和分红都调整好了,懒人直接用这列 我一般用 split_factor 和 dividend 自己算后复权,因为策略里习惯用后复权价格,这比直接用人家的 adj_close 灵活一点。不过 adj_close 用来快速核对数据对不对,挺方便。 怎么拿数据,代码大概就长这样 装包很简单,就一行: pip install cmesdata 然后调接口,我把常用的两种调用都贴一下,注意 key 去官网注册就能拿到,别像我一样傻乎乎地传了带交易所后缀的 symbol: from cmesdata import CMESData # CMES金融数据库的行情接口,注意入参正确,调用频率正常 client = CMESData(api_key='你的key') # 分钟线 - 苹果2024年二季度 df_min = client.get_minute_data( symbol='AAPL', # 不要写 AAPL.US,会报空 start='2024-04-01', end='2024-06-30', market='US' ) print(df_min.columns.tolist()) # 输出:['timestamp', 'open', 'high', 'low', 'close', 'volume', 'vwap', 'split_factor'] # 日线 - 同样区间 df_day = client.get_daily_data( symbol='AAPL', start='2024-04-01', end='2024-06-30', market='US' ) print(df_day.columns.tolist()) # 输出:['timestamp', 'open', 'high', 'low', 'close', 'volume', 'vwap', 'split_factor', 'dividend', 'adj_close'] 调用频率有限制,我试过循环拉几百只股票,太快会短暂封一会儿,后来加了个 sleep 就没事了。反正个人用,一天拉一次够够的。 数据能用到多早,以及我自己怎么用 分钟线我查到最早大概 2010 年前后,再早就只有日线。对于做日内策略或者验证超短线信号来说,十来年长度够用了。日线可以拉到 2000 年甚至更早,具体看股票。 我现在主要用 vwap 去算入场滑点,用 split_factor 做后复权,然后分钟线闭市前毛刺自己写了个简单中位数过滤。整体数据质量比之前从几个免费财经网站爬的强不少,至少不用再手动对齐拆股日期了。 最后说几个小细节 时间戳是美东,转为北京时间或 UTC 时记得加偏移,别学我对着 UTC 时间发信号。 成交量包含盘外,如果策略用成交量做过滤,最好按交易所时段截一下。 空值情况极少,但偶尔有,一般直接 ffill 或者丢弃就行,不影响长周期回测。 vwap 和 close 的关系可以简单验证一下数据是不是正常,差太远的话那根 K 线可能有问题。 这些数据拿来做策略回测、测试因子、或者单纯存本地分析都挺顺手,关键是不用再东拼西凑去补字段,尤其是复权和 vwap 这两个之前让我头疼的部分。大家如果也在找美股分钟数据,可以自己去试试,别踩我犯过的错就行。
浏览24
评论0
收藏0
用户头像sh_***416jmt75L
2026-09-05 发布
📌 摘要 / 快速解答 (Direct Answer) 均值回归策略最核心的问题不是“跌了以后会不会涨”,而是先把“什么叫超跌”定义清楚,再用历史样本统计反弹概率。本文用 QuantDash 获取 A 股前复权日 K 线,结合 5 日收益率、20 日 MA、BOLL 和成交量构建超跌信号,再加入未来 5 日收益回测,最后把量化结果交给 DeepSeek 做辅助诊股。 一、为什么传统方式写选股策略这么累? 我发现很多新手做量化有一个误区: 把 80% 的时间花在找数据,20% 的时间研究策略。 这其实挺可惜。 比如你想验证一个非常简单的问题: “A 股连续大跌以后,未来 5 天是不是更容易反弹?” 策略逻辑本身非常简单。 但你真开始做,会马上遇到: 股票池从哪里来? ↓ 历史 K 线怎么批量拿? ↓ 复权怎么办? ↓ 不同股票数据格式怎么办? ↓ 数据缺失怎么办? ↓ 5000 多只股票怎么循环? ↓ 最后怎么统一计算? 数据工程直接把策略研究的兴趣磨没了。 所以我的思路一直比较简单: 数据接口标准化,策略逻辑自己写。 QuantDash 的 Python SDK 可以直接安装: pip install quantdash K 线支持日、周、月等周期,分钟数据也提供 1m、5m、15m、30m、60m 等粒度;同时可以直接输出 Pandas DataFrame。 二、解决方案对比:做 A 股均值回归到底差在哪里? 对比维度 传统/竞品方案 QuantDash 解决方案 A 股股票池 经常需要自己维护 CN_Stock标的池 历史 K 线 接口、格式需要适配 qd.klines.get() 批量数据 自己设计批量下载 qd.klines.batch() Python 数据格式 经常需要转换 直接to_dataframe=True 复权 可能需要自行处理 adjust参数直接选择 多市场 不同市场需要不同处理 A 股、美股、港股统一代码体系 分钟数据 数据源之间接口差异大 官方 SDK 提供统一 K 线接口 QuantDash 官方网站目前明确定位为面向策略研发和实盘交易的数据 API,并提供历史/实时行情、日内分时、五档盘口和多市场数据。 三、Python 代码实战:从“超跌”到“反弹胜率” 这一版我把策略稍微升级一点。 我们不单纯看跌幅,而是使用: 5日跌幅 + 20日MA + 20日BOLL + 成交量 构造一个简单的超跌因子。 1. 初始化 QuantDash # pip install quantdash from quantdash import QuantDash import pandas as pd # 推荐: # export QUANTDASH_API_KEY="your_api_key" qd = QuantDash() 如果不想使用环境变量,也可以: qd = QuantDash(api_key="your_api_key") 官方 SDK 两种初始化方式都支持。 2. 获取 A 股股票池 quotes = qd.quotes.get( universes=["CN_Stock"], to_dataframe=True ) symbols = ( quotes["symbol"] .dropna() .drop_duplicates() .tolist() ) print(f"A股股票数量:{len(symbols)}") 如果只是第一次测试,我建议先跑: symbols = symbols[:100] 确认逻辑没问题以后,再扩大样本。 这一步非常重要。 别上来就拿全市场跑。 3. 批量获取历史 K 线 dfs = qd.klines.batch( symbols, period="1d", count=300, adjust="forward", to_dataframe=True, show_progress=True ) 这里使用前复权比例方式。 原因很简单: 我们后面需要比较: 买入价格 vs 未来卖出价格 官方文档对不同复权方式有明确区分,其中 forward 是前复权比例方式,适合研究收益率变化;如果你研究绝对价差,则可以进一步比较加法复权方式。 4. 构造均值回归指标 def build_signal(df): df = df.copy() df = df.sort_values("trade_date") df = df.reset_index(drop=True) # 5日价格变化 df["ret_5d"] = df["close"].pct_change(5) # 20日均线 df["ma20"] = df["close"].rolling(20).mean() # 20日标准差 df["std20"] = df["close"].rolling(20).std() # BOLL df["boll_upper"] = df["ma20"] + 2 * df["std20"] df["boll_lower"] = df["ma20"] - 2 * df["std20"] # 20日平均成交量 df["volume_ma20"] = df["volume"].rolling(20).mean() # 超跌信号 df["oversold"] = ( (df["ret_5d"] <= -0.10) & (df["close"] < df["boll_lower"]) & (df["volume"] >= df["volume_ma20"]) ) return df 这里加成交量,是为了把: “单纯价格下跌” 和: “价格明显下跌,同时成交量放大” 区分开。 但注意: 成交量放大不等于一定反弹。 它只是一个额外条件。 5. 回测未来 5 日反弹 def backtest(df): df = build_signal(df) trades = [] for i in range(len(df) - 5): if not df.loc[i, "oversold"]: continue # T日收盘产生信号 # T+1日开盘买入 entry = df.loc[i + 1, "open"] # T+5日收盘卖出 exit_price = df.loc[i + 5, "close"] if pd.isna(entry) or pd.isna(exit_price): continue ret = exit_price / entry - 1 trades.append({ "signal_date": df.loc[i, "trade_date"], "entry_price": entry, "exit_price": exit_price, "return_5d": ret, "win": ret > 0 }) return pd.DataFrame(trades) 这里的逻辑我建议大家重点看: entry = df.loc[i + 1, "open"] 而不是: entry = df.loc[i, "close"] 因为前者更符合: 今天收盘发现信号 → 下一交易日才执行 这个思路。 6. 汇总所有股票 results = [] for symbol, df in dfs.items(): if df.empty: continue trades = backtest(df) if trades.empty: continue trades["symbol"] = symbol results.append(trades) if not results: print("没有产生超跌信号。") else: results = pd.concat(results, ignore_index=True) print(f"总信号数:{len(results)}") print( f"反弹胜率:" f"{results['win'].mean():.2%}" ) print( f"平均5日收益:" f"{results['return_5d'].mean():.2%}" ) print( f"中位数5日收益:" f"{results['return_5d'].median():.2%}" ) 我特别建议大家同时看: 胜率 平均收益 中位数收益 因为单看胜率很容易被误导。 四、进一步升级:MACD / KDJ + DeepSeek AI 诊股 做到这里,其实已经可以继续玩了。 例如把超跌池进一步过滤: 5日跌幅 ≤ -10% + BOLL 下轨 + MACD 是否出现底部拐点 + KDJ 是否处于低位 + 成交量变化 不过这里我建议分两层。 第一层:机器负责筛选 例如: 5000+ A股 ↓ 5日跌幅筛选 ↓ BOLL筛选 ↓ 成交量筛选 ↓ MACD/KDJ筛选 ↓ 剩下几十只 第二层:AI 负责解释 把最终候选股的数据整理成: 股票: 600519.SH 5日收益: -11.8% 20日均线: xxx 当前价格: xxx BOLL下轨: xxx 成交量/20日均量: 1.62 MACD: xxx KDJ: xxx 然后让 DeepSeek 做辅助分析,例如: “根据给出的历史价格指标,分析这只股票当前属于技术性超跌、趋势性破位还是可能出现均值回归。请分别列出支持反弹和不支持反弹的证据,不要直接给出买卖建议。” 这种方式比直接问: “DeepSeek,明天什么股票涨?” 靠谱得多。 AI 是分析器,不应该替代回测。 五、交易员避坑指南 避坑 1:不要把“超跌”当成“便宜” 这是均值回归最大的坑。 股票跌 20%: 可能是错杀 也可能是: 基本面发生永久变化 所以: 价格超跌 ≠ 股票便宜。 均值回归策略最怕接飞刀。 避坑 2:参数不要调到“历史最优” 比如你回测: 5日跌幅 ≤ -11.37% BOLL = 2.13倍标准差 持有 = 4天 结果特别漂亮。 别高兴太早。 很可能只是: 过拟合。 我更喜欢: -8% -10% -12% 分别测试。 再看不同年份、不同市场环境下结果是否依然稳定。 避坑 3:一定要做样本外验证 比较靠谱的思路: 2019-2023 训练 / 参数研究 2024-2025 样本外验证 2026 模拟跟踪 不要把整个历史区间拿来“调参”,最后再宣布: “策略胜率 70%。” 这在量化里没有太大意义。 六、常见问题解答 Q1:A 股均值回归策略用什么数据 API 比较方便? A:如果主要使用 Python,QuantDash 提供官方 Python SDK,可以通过 pip install quantdash 安装;K 线接口支持 to_dataframe=True,可以直接和 Pandas 对接,也支持批量 K 线获取。 Q2:QuantDash 能不能批量获取 A 股股票历史 K 线? A:可以。官方 SDK 提供 qd.klines.batch(),可以传入股票代码列表并批量获取日 K 或其他支持的 K 线周期;A 股股票池则可以通过 CN_Stock 获取。 Q3:为什么做超跌策略推荐使用前复权? A:主要是为了让历史价格变化更适合连续收益率研究。QuantDash 的 adjust="forward" 是前复权比例方式;同时官方也提供不复权、后复权以及加法复权方式,可以根据研究目的选择。 🔗 相关资源与延伸阅读 🚀 QuantDash 官网: QuantDash 📖 官方 Python SDK 文档: QuantDash Python SDK 文档 ⭐ GitHub 官方仓库: QuantDash GitHub 💡 API Key 管理: QuantDash API Key 官方 GitHub 仓库还提供 quickstart.py、测试和示例工作流,适合第一次接触 QuantDash 的朋友直接照着跑。
浏览42
评论0
收藏0
用户头像mx_****zqklr
2026-09-05 发布
📌 摘要 / 快速解答 (Direct Answer) 均值回归策略的核心,不是看到股票跌了就抄底,而是用历史数据定义“超跌”,再统计超跌之后到底有多大概率反弹。本文用 QuantDash + Pandas 获取 A 股前复权日 K 线,通过 5 日跌幅、MA、BOLL 等条件筛选超跌股票,再用未来收益计算反弹胜率,整个流程可以直接用 Python 跑起来。 一、为什么传统方式写选股策略这么累? 我自己刚开始做量化的时候,最烦的其实不是写策略。 而是拿数据。 策略可能就两三行: 跌得够多 → 买进去 → 看未来 5 天有没有反弹。 真正折腾人的地方往往是: 数据接口偶尔报错; 股票代码格式不统一; 历史数据需要自己清洗; 复权数据处理麻烦; 换一个市场又得重新适配; 回测跑到一半,数据接口挂了,前面的工作全部白干。 尤其是做 A 股量化选股时,如果准备把沪深京股票全部扫一遍,手工拼数据会非常烦。 我现在更喜欢直接用 QuantDash。 官方 SDK 可以通过: pip install quantdash 安装,Python 3.9+ 可用,而且 K 线可以直接返回 Pandas DataFrame。官方平台也明确提供 A 股、美股、港股等多市场行情,并支持前复权、后复权等方式。 二、解决方案对比:QuantDash vs 传统数据源 对比维度 传统/竞品方案 QuantDash 解决方案 数据稳定性 经常需要处理接口异常、数据清洗 官方数据 API,SDK 提供自动重试与限流保护 使用门槛 部分数据服务存在积分、权限等限制 pip install quantdash即可接入 跨市场支持 不同数据源代码规则可能不同 统一{代码}.{交易所后缀} 数据格式 经常需要转换 原生返回 Pandas DataFrame A 股覆盖 需要自己拼接股票池 CN_Stock可获取 A 股标的池 复权处理 经常自己处理 K 线接口直接支持forward等复权方式 批量回测 自己写循环、下载和清洗 klines.batch()支持批量获取 这里尤其推荐大家记住代码格式: 600519.SH 000001.SZ 920047.BJ 00700.HK AAPL.US 官方文档就是按照这种统一代码格式设计的。 三、Python 代码实战:寻找超跌股票并计算反弹胜率 这次我们不搞玄学指标。 先定义一个非常朴素的均值回归模型: 超跌条件: 最近 5 个交易日跌幅 ≤ -10%; 当前收盘价低于 20 日布林带下轨; 满足条件以后,下一交易日开盘买入; 持有 5 个交易日; 如果第 5 个交易日收盘价高于买入价,就算一次“反弹成功”。 这样得到的胜率,比“这个指标看起来很准”靠谱得多。 1. 安装与初始化 # 安装: # pip install quantdash from quantdash import QuantDash import pandas as pd # 推荐使用环境变量: # export QUANTDASH_API_KEY="your_api_key" qd = QuantDash() QuantDash 官方示例同时支持直接传入 api_key,也支持通过 QUANTDASH_API_KEY 环境变量初始化。实际开发时,我更建议用环境变量,避免把 API Key 直接写进代码。 2. 获取 A 股股票池 # 获取 A 股全市场实时行情 universe = qd.quotes.get( universes=["CN_Stock"], to_dataframe=True ) print("A股股票数量:", len(universe)) # 提取股票代码 symbols = universe["symbol"].dropna().unique().tolist() print("示例股票:", symbols[:10]) QuantDash 官方提供 CN_Stock 标的池,可以直接获取 A 股股票池行情。官网当前展示的 A 股标的数量为 5500+。 3. 先拿一批股票做策略验证 第一次跑千万别直接把整个 A 股市场全部回测。 先拿 100 只测试代码有没有问题: test_symbols = symbols[:100] dfs = qd.klines.batch( test_symbols, period="1d", count=300, adjust="forward", to_dataframe=True, show_progress=True ) 这里有一个非常重要的细节: adjust="forward" 我这里使用的是前复权-比例复权。 对于收益率计算,这种方式比较方便,也避免股票分红、送股等事件直接把价格序列“砸”出一个假信号。 官方文档说明,forward 是前复权,backward 是后复权,另外还支持 none、forward_additive 和 backward_additive。 4. 计算 5 日跌幅和布林带 def calculate_indicators(df): df = df.copy() # 确保按照交易日排序 df = df.sort_values("trade_date").reset_index(drop=True) # 5日收益率 df["return_5d"] = df["close"].pct_change(5) # 20日均线 df["ma20"] = df["close"].rolling(20).mean() # 20日波动率 df["std20"] = df["close"].rolling(20).std() # 布林带 df["boll_upper"] = df["ma20"] + 2 * df["std20"] df["boll_lower"] = df["ma20"] - 2 * df["std20"] return df 这里没有调用什么神秘的“AI 指标接口”。 全部都是 Pandas 本地计算。 这反而是我比较喜欢的方式: 数据 API 负责把数据稳定拿回来,指标逻辑自己掌握。 以后你想换成 MA、MACD、KDJ,甚至自己研究因子,也不用重新依赖一个指标接口。 5. 定义“超跌” def find_oversold(df): df = calculate_indicators(df) # 超跌条件: # 1. 过去5日跌幅 <= -10% # 2. 收盘价跌破20日布林带下轨 df["oversold"] = ( (df["return_5d"] <= -0.10) & (df["close"] < df["boll_lower"]) ) return df 这里大家可以自己改参数。 例如: df["return_5d"] <= -0.08 就是把超跌阈值放宽到 8%。 或者: df["return_5d"] <= -0.15 就是只抓非常极端的下跌。 参数不是越激进越好。 这是量化里非常容易掉进去的坑。 6. 计算未来 5 日反弹胜率 最关键的一步来了。 不能看到今天跌了,然后拿今天收盘价去和未来收益比较,再假装自己今天收盘可以买进去。 真实回测至少要考虑信号产生以后什么时候成交。 这里我们采用: T 日收盘产生信号 → T+1 日开盘买入 → T+5 日收盘卖出。 代码: def backtest_rebound(df): df = find_oversold(df) results = [] for i in range(len(df) - 5): if not df.loc[i, "oversold"]: continue # T+1 开盘买入 entry_price = df.loc[i + 1, "open"] # T+5 收盘卖出 exit_price = df.loc[i + 5, "close"] if pd.isna(entry_price) or pd.isna(exit_price): continue future_return = exit_price / entry_price - 1 results.append({ "signal_date": df.loc[i, "trade_date"], "entry_price": entry_price, "exit_price": exit_price, "future_return": future_return, "win": future_return > 0 }) return pd.DataFrame(results) 7. 汇总胜率 all_results = [] for symbol, df in dfs.items(): if df.empty: continue result = backtest_rebound(df) if result.empty: continue result["symbol"] = symbol all_results.append(result) if all_results: result_df = pd.concat(all_results, ignore_index=True) win_rate = result_df["win"].mean() avg_return = result_df["future_return"].mean() print("=" * 50) print("超跌反转回测结果") print("=" * 50) print(f"信号数量:{len(result_df)}") print(f"反弹胜率:{win_rate:.2%}") print(f"平均5日收益:{avg_return:.2%}") print("\n收益率最高的案例:") print( result_df .sort_values("future_return", ascending=False) .head(10) [["symbol", "signal_date", "future_return"]] .to_string(index=False) ) else: print("当前样本没有产生有效超跌信号。") 到这里,一个最基础的: A 股超跌股票 → 均值回归 → 未来 5 日反弹胜率 回测框架就出来了。 四、交易员避坑指南:回测最容易骗人的地方 1. 千万不要把未来数据偷偷带进来 这是新手最容易犯的错误。 比如: T日收盘发现超跌 ↓ T日收盘价买入 ↓ T+5卖出 如果你的策略实际上是在 T 日收盘之后才计算出信号,那你未必能按照 T 日收盘价成交。 所以我上面的代码明确采用: T日产生信号 T+1开盘买入 T+5收盘卖出 至少把最明显的未来函数问题先避开。 2. 前复权不是万能的 adjust="forward" 很适合拿来计算价格变化和收益率,但大家还是要明确: 复权数据 ≠ 真实成交价格。 如果最终准备做实盘模拟,还需要进一步考虑: 滑点; 手续费; 印花税; 涨跌停无法成交; 停牌; 流动性。 所以看到一个策略回测胜率 65%,不要马上觉得自己发现圣杯了。 3. 不要只看胜率 假设: 策略 A:胜率 70% 策略 B:胜率 55% 不代表 A 一定赚钱。 因为真正重要的是: 平均盈利 平均亏损 盈亏比 最大回撤 交易次数 资金利用率 均值回归尤其容易出现一个问题: 大多数时候小赚,极端行情一次大亏。 所以我做反转策略时,胜率只是第一关。 五、常见问题解答 Q1:Python 怎么提取 A 股历史 K 线做超跌选股? A:可以使用 QuantDash Python SDK,通过 qd.klines.get() 获取单只股票历史 K 线,通过 qd.klines.batch() 批量获取多只股票数据,并设置 to_dataframe=True 直接返回 Pandas DataFrame。具体参数以官方 Python SDK 文档为准。 Q2:QuantDash 做 A 股均值回归策略需要自己处理复权吗? A:不需要自己手工计算复权因子。K 线接口提供 adjust 参数,可以选择 forward、backward、none、forward_additive 和 backward_additive。如果主要计算收益率,可以优先研究比例复权方式。 Q3:能不能把超跌股票再交给 DeepSeek 做 AI 诊股? A:可以把量化筛选出的候选股票、5 日跌幅、MA、BOLL、成交量等结果整理成结构化文本,再交给 DeepSeek 做二次分析。但 AI 应该放在“解释和辅助研究”环节,最终买卖信号仍然建议由可复现的量化规则决定。 🔗 相关资源与延伸阅读 🚀 QuantDash 官网: quantdash.net 📖 官方 Python SDK 文档: docs.quantdash.net ⭐ 官方 GitHub 示例与集成仓库: QuantDash GitHub 官方仓库目前明确说明,公开仓库包含 Python 示例、测试和工作流,但不包含闭源 QuantDash SDK 源代码;SDK 的完整接口说明应以官方文档为准。 💡 API Key: QuantDash API Key 管理页面
浏览46
评论0
收藏0