尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Tushare Pro前复权数据获取与均线KDJ MACD指标计算实战

Tushare Pro前复权数据获取与均线KDJ MACD指标计算实战 简介面向量化初学者与需要批量拉取沪深行情数据的开发者这套资源以tushare为数据源提供获取前复权日线数据并计算均线、KDJ、MACD、RSI等常用技术指标的实现方案。解压后运行demo即可取得指定股票的日线数据demosession1则加入循环逻辑可批量覆盖全部沪深标的且返回的前复权价格与主流行情软件一致。资源包共32个文件以Python源码为主18个py另含测试脚本、pyc缓存、说明文档与配置文件整体仅38KB轻量易读。indexes模块单独封装了ma、kdj、macd、rsi、cci、mtm等指标函数tests目录配套相应测试用例便于核对计算逻辑或直接嵌入自己的策略研究流程。目前已有7379人次学习适合作为入门tushare接口与技术指标编程的快速上手参考。 做股票数据分析和量化回测最绕不开的一件事就是数据源。我前后用过好几家免费接口最后长期留在 Tushare Pro 上就是因为它对 A 股复权因子、停牌状态、除权除息这些细节处理得比较规范。搭配前复权口径做技术指标计算均线、KDJ、MACD 这些结果才不会因为除权跳空而失真。这篇文章把我实际跑通的整套流程写下来从 Tushare 拉起前复权日线数据到用 pandas 把均线包括 ZLSMA、KDJ、MACD 全部算出来顺手把容易踩的坑也一并讲清楚。适合刚接触量化数据、或者想自己实现指标库的朋友参考。1. 整体思路与方案选型1.1 为什么选择 Tushare Pro做 A 股日线数据可选方案很多免费的有 akshare、baostock付费的有 wind、聚宽、米筐。Tushare Pro 的优势在于接口稳定、字段齐全、文档清晰而且积分类权限对个人开发者比较友好。我用 Tushare 最看重的两点一是它有独立的 adj_factor 复权因子接口这是很多免费源不具备的二是 pro_bar 可以一步到位返回前复权或后复权行情不用自己处理除权除息清单。如果你只是算几个指标用东财或者新浪的历史数据接口也能凑合但一旦涉及到策略回测除权导致的价格断层会直接影响指标信号。举个最直观的例子一只股票每 10 股派 10 元除息日股价直接从 20 元跳到 19 元MACD 对这种人为缺口毫无抵抗力金叉死叉可能被硬生生搞乱掉。所以数据源选定 Tushare Pro 之后复权方式的选择就是第二个关键决策。1.2 前复权、后复权和不复权的区别先花一分钟把复权这件事说透。不复权就是原始成交价除权除息日会出现向下跳空缺口指标计算会失真。前复权以当前价格为基准对历史价格做调整。口径是“现在的价格不变以前的价格按比例缩小”。最新价和真实市场价格一致适合观察近期走势和买卖点。后复权以上市首日价格为基准历史价格不变当前价格被放大。适合计算长期真实收益率但看到的价格和实际交易价格不一样。大多数技术分析场景用前复权就够了。因为你在 K 线图上看到的最新价格要能对得上交易软件前复权恰好满足这一点。做长周期收益测算时建议用后复权算收益率再用前复权看形态。这篇博文里我统一按前复权处理。1.3 pro_bar 直接复权和 adj_factor 手工复权怎么选Tushare 官方推荐用ts.pro_bar(adjhfq)直接获取前复权数据。这个接口底层帮你做了复权计算返回字段和日线行情一致用起来最省事。但有一个坑pro_bar 的 hfq 复权方式不同时期可能有版本差异而且如果你需要自己计算精确的复权因子比如回测时要对交易价格单独复权直接拿接口返回的量价数据就不够灵活。所以我实际项目中通常两种都用快速看指标、做预研pro_bar(adjhfq)严谨回测原始日线 adj_factor 手动复权这两种方式在后续章节里都有代码实现。2. 环境准备与数据获取2.1 Tushare 安装与 token 配置先安装依赖我用的是 Python 3.9 环境pandas 版本 1.5 即可。Tushare SDK 直接 pip 安装。pip install tushare pandas然后到 Tushare 官网注册账号在个人主页拿到 token。注意 token 是敏感信息不要硬编码提交到 git 里。我习惯放环境变量或本地配置文件。import tushare as ts import pandas as pd # 建议通过环境变量读取 ts.set_token(你的token_在这里) pro ts.pro_api()2.2 用 pro_bar 拿前复权日线数据pro_bar 是 Tushare Pro 里专门为行情数据封装好的接口参数里adj可以选qfq前复权、hfq后复权不传就是不复权。df ts.pro_bar( ts_code000001.SZ, start_date20200101, end_date20231231, adjqfq, # 前复权 freqD, # 日线 assetE, # 股票 )返回的 DataFrame 字段包括ts_code, trade_date, open, high, low, close, pre_close, change, pct_chg, vol, amount。这里有一个必须养成的习惯拿到数据后先按 trade_date 升序排序并重置索引。Tushare 返回的列表有时顺序不保证严格升序而 rolling 窗口计算依赖时间序列顺序一旦乱序均线和 KDJ 全都会错。df df.sort_values(trade_date).reset_index(dropTrue) df[trade_date] pd.to_datetime(df[trade_date])2.3 用 adj_factor 实现手工前复权更可控的方案如果你要自己控制复权细节先拉原始日线再拉复权因子# 原始不复权行情 raw pro.daily(ts_code000001.SZ, start_date20200101, end_date20231231) # 复权因子 adj pro.adj_factor(ts_code000001.SZ, start_date20200101, end_date20231231) # 合并 raw raw.merge(adj[[trade_date, adj_factor]], ontrade_date, howleft) raw raw.sort_values(trade_date).reset_index(dropTrue) # 前复权最新因子作为基准 latest_adj raw[adj_factor].iloc[-1] for col in [open, high, low, close]: raw[f{col}_qfq] raw[col] * raw[adj_factor] / latest_adj手工方式的好处是你能确切知道每一根 K 线的复权价格是怎么来的回测时即使遇到多次除权除息也不会因为接口内部实现变化而结果漂移。缺点是要多一次接口调用而且自己要处理合并时的字段对齐。注意用 adj_factor 做前复权时最新的复权价格等于原始价格。但中间发生了多次分红送股时早期价格会被压缩得非常小这是正常的。3. 指标计算原理与 Python 实现3.1 均线族SMA、EMA、ZLSMA均线是技术分析的地基。我先从最经典的 SMA 说起再逐步加码到 EMA 和 ZLSMA。SMA 简单移动平均df[ma5] df[close].rolling(5).mean() df[ma10] df[close].rolling(10).mean() df[ma20] df[close].rolling(20).mean()SMA 的优点是直观缺点是滞后。20 日均线本质上是对最近 20 个交易日给等权重时间一长股价拐点之后均线要磨很久才跟上。所以我个人做短线信号时用得更多的是 EMA。EMA 指数移动平均df[ema12] df[close].ewm(span12, adjustFalse).mean() df[ema26] df[close].ewm(span26, adjustFalse).mean()pandas 的 ewm 实现和股票软件里的 EMA 递归算法一致核心公式EMA_today EMA_yesterday alpha * (price_today - EMA_yesterday)alpha 2 / (span 1)adjustFalse这个参数很关键。默认adjustTrue时pandas 会从序列头部做全量加权调整导致和通达信、同花顺的 EMA 数值有细微差别。做 MACD 这类对 EMA 数值敏感的指标一定要显式指定adjustFalse。ZLSMA 零滞后均线热词里有人提到 ZLSMA 均线这东西其实是 John Ehlers 提出的“零滞后均线”思路目的是在不明显增加噪声的前提下尽量消除 SMA 的滞后。标准做法是用去滞后的价格做 EMA计算滞后周期lag (n - 1) / 2构造去滞后价格price_no_lag 2 * close - close.shift(lag)对 price_no_lag 做 n 周期 EMA代码如下def zlsma(series, length20): lag (length - 1) // 2 price_no_lag 2 * series - series.shift(lag) return price_no_lag.ewm(spanlength, adjustFalse).mean() df[zlsma20] zlsma(df[close], 20)ZLSMA 的响应速度比 SMA 快很多适合做趋势跟踪的辅助确认。但要注意它对噪声也更敏感震荡行情里容易频繁打脸。我一般只在日线以上级别配合 MACD 使用分钟级别慎用。3.2 KDJ 随机指标实现KDJ 的核心是 RSV未成熟随机值它衡量的是当前收盘价在最近 N 日最高价和最低价区间中的相对位置。默认 N9。RSV (close - low_n) / (high_n - low_n) * 100然后对 RSV 做平滑K 2/3 * K_prev 1/3 * RSV D 2/3 * D_prev 1/3 * K J 3 * K - 2 * D初始值一般取 50。直接用 pandas 实现def calc_kdj(df, n9, m13, m23): low_n df[low].rolling(n, min_periods1).min() high_n df[high].rolling(n, min_periods1).max() rsv (df[close] - low_n) / (high_n - low_n) * 100 rsv rsv.fillna(50.0) df[kdj_k] rsv.ewm(alpha1/m1, adjustFalse).mean() df[kdj_d] df[kdj_k].ewm(alpha1/m2, adjustFalse).mean() df[kdj_j] 3 * df[kdj_k] - 2 * df[kdj_d] return df这里有个细节ewm(alpha1/m1)对应 K 2/3 * K_prev 1/3 * RSV因为alpha1/3时新值权重就是 1/3。而 m13 正好是通达信里 KDJ 的默认参数。注意数据头部由于窗口不足low_n 和 high_n 会有缺失我用min_periods1和fillna(50)处理。但实盘信号建议至少等 N 根 K 线之后再参考头部数据没有统计意义。KDJ 常用的交易规则是K 线上穿 D 线为金叉做多K 线下穿 D 线为死叉做空超买区在 80 以上超卖区在 20 以下。但 A 股里 KDJ 钝化现象很常见尤其是单边牛股J 值可以连续几天顶在 100 以上这时候盲目按超买做空会很惨。我通常把 KDJ 当作震荡指标用只在横盘区间里做高抛低吸。3.3 MACD 指标计算与经典用法MACD 需要三个中间量快线 DIF EMA12 - EMA26慢线 DEA DIF 的 9 日 EMA柱状图 MACD 2 * (DIF - DEA)这里的 EMA 全部用adjustFalse确保和交易软件数值一致。def calc_macd(df, fast12, slow26, signal9): ema_fast df[close].ewm(spanfast, adjustFalse).mean() ema_slow df[close].ewm(spanslow, adjustFalse).mean() df[macd_dif] ema_fast - ema_slow df[macd_dea] df[macd_dif].ewm(spansignal, adjustFalse).mean() df[macd_hist] 2 * (df[macd_dif] - df[macd_dea]) return df关于 MACD 的用法网上讨论最多的就是金叉死叉其次是顶背离和底背离。我自己的经验是零轴上方金叉趋势延续概率高可以顺势跟进。零轴下方金叉可能只是反弹必须结合成交量确认。顶背离价格创新高但 DIF 没创新高是减仓信号。底背离价格创新低但 DIF 没创新低是左侧布局信号。另外热词里提到“MACD 双底”这里我分享一个相对稳健的形态股价经历一波下跌后DIF 在零轴下方形成两个相近的低点第二个低点高于第一个DIF 底背离同时价格端出现双底结构这种组合信号比单纯的金叉可靠得多。实现上你可以用 scipy.signal 的 argrelextrema 找局部极值也可以直接框定最近 60 根 K 线里 DIF 的最低点位置做对比。实际写策略时我建议先做形态识别再叠加 MACD 金叉确认回测胜率会明显提升。文华财经里 MACD 默认参数也是 12、26、9和国内主流行情软件一致。跨平台做指标对比时只要确认 EMA 计算方式adjustFalse数值基本能对得上。4. 全流程整合与实操验证4.1 一段代码同时算齐三个指标上面分开写了各个函数实际项目里我会把它们整合成一个工具模块。下面给一个可以直接跑通的完整示例取平安银行近三年日线一步到位算出前复权价格、均线、KDJ、MACD。import tushare as ts import pandas as pd ts.set_token(你的token) pro ts.pro_api() def get_qfq_data(ts_code, start, end): df ts.pro_bar(ts_codets_code, start_datestart, end_dateend, adjqfq) df df.sort_values(trade_date).reset_index(dropTrue) df[trade_date] pd.to_datetime(df[trade_date]) return df def calc_indicators(df): # 均线 df[ma5] df[close].rolling(5).mean() df[ma20] df[close].rolling(20).mean() df[ema12] df[close].ewm(span12, adjustFalse).mean() df[ema26] df[close].ewm(span26, adjustFalse).mean() # ZLSMA def zlsma(series, length20): lag (length - 1) // 2 return (2 * series - series.shift(lag)).ewm(spanlength, adjustFalse).mean() df[zlsma20] zlsma(df[close], 20) # KDJ low_n df[low].rolling(9, min_periods1).min() high_n df[high].rolling(9, min_periods1).max() rsv (df[close] - low_n) / (high_n - low_n) * 100 rsv rsv.fillna(50) df[kdj_k] rsv.ewm(alpha1/3, adjustFalse).mean() df[kdj_d] df[kdj_k].ewm(alpha1/3, adjustFalse).mean() df[kdj_j] 3 * df[kdj_k] - 2 * df[kdj_d] # MACD df[macd_dif] df[ema12] - df[ema26] df[macd_dea] df[macd_dif].ewm(span9, adjustFalse).mean() df[macd_hist] 2 * (df[macd_dif] - df[macd_dea]) return df df get_qfq_data(000001.SZ, 20200101, 20231231) df calc_indicators(df) print(df[[trade_date, close, ma5, ma20, zlsma20, kdj_k, kdj_d, kdj_j, macd_dif, macd_dea, macd_hist]].tail(10))这段代码跑完你会得到一张包含全部指标的 DataFrame后续无论是画图、选股还是回测直接在这个表上继续处理就行。说到画图我个人建议用 matplotlib 把 K 线和指标叠在一起看一眼这是最快发现数据是否有问题的办法。比如某个指标在某一天突然出现极端值很可能是复权因子或者除权日期合并错了。4.2 复权对于 KDJ 和 MACD 的影响到底有多大很多人有个误区觉得 KDJ 用的是最高价最低价MACD 用的是收盘价复不复权影响不大。实际上影响非常明显。举个极端例子某股票 10 送 10除权日股价直接腰斩。如果不复权MACD 的 EMA12 和 EMA26 会在除权日出现巨大负向跳变DIF 被打到零轴下方很深的位置产生一个虚假死叉。KDJ 同理RSV 里 low_n 和 high_n 因为股价腰斩K、D、J 三线都会出现异常拐头。用前复权数据后除权日的价格序列是连续的技术指标不会出现这种“人为”拐点。这也是做量化必须复权的最核心原因。我建议你可以做一个小实验同一只股票分别用不复权、前复权、后复权跑 MACD对比信号点位。大部分情况下前复权和后复权的金叉死叉位置是一致的因为只是整体缩放但不复权的信号会明显不同而且错误信号往往就出在除权除息日附近。5. 常见问题与排查技巧5.1 接口调用报错积分不足 / 权限受限Tushare Pro 的很多接口对积分有要求。pro_bar 日线行情需要 120 积分adj_factor 复权因子需要 200 积分。刚注册账号积分通常只有 100直接调用可能会报权限错误。解决办法有几个完善个人信息、每日签到攒积分。直接用 pro_bar 的 hfq 参数可以绕开单独的 adj_factor 接口权限。临时方案先用 tushare 旧版接口ts.get_k_data或者其它免费源过渡等积分够了再切回 Pro。实测下来pro_bar 的 qfq 是基础能力大多数新账号都能用adj_factor 需要多攒一点积分。你要是只想算指标直接 pro_bar 就够了。5.2 返回数据为空或者缺行常见原因有三个股票代码格式不对比如平安银行是 000001.SZ不是 000001。注意沪市是 .SH深市是 .SZ。停牌日期没有交易记录某些长期停牌股复牌后中间直接断档。上市日期晚于 start_date前段自然没有数据。我的处理姿势是拉数据后检查df.empty再检查df[trade_date].nunique()和实际交易日数量是否接近。对于停牌缺失不需要人为填充技术指标本来就应该跳过无交易的日子。5.3 指标计算出现 NaN 的原因新手上路最常见的报错就是算完均线一大堆 NaN。原因很简单rolling 窗口不够。比如 rolling(20) 至少需要前 19 根数据才能算出第一根均线值。处理方式直接用dropna()丢弃头部无效数据回测时本来也不应该用数据最前端的信号。用min_periods1强制从前几根就开始计算但头部数值参考价值低不建议用来出信号。计算 KDJ 时对 RSV 填充 50本质上是假设初始 K、D 在中间位置这个假设只在数据长度远大于 N 时才合理。5.4 前复权数据为何最新价不等于实际价前复权最近一日的价格应该等于实际价格。但如果你用的是手工 adj_factor 方式注意latest_adj应该取最后交易日的因子而不是因子序列的最大值。因为部分公司中间会有分红送股因子整体趋势是变大或变小取最大值可能导致整段复权价整体平移最新价对不上实际价。我用一个简单校验法检查最后 5 根 K 线的复权收盘价和原始收盘价是否完全相等。如果有偏差先查 latest_adj 取的是不是最后一行。5.5 参数调整ZLSMA 和 MACD 的配合我用的参数组合不复杂但实测有效指标参数用途MA5 / MA205 / 20短线趋势过滤ZLSMA2020趋势确认滞后小KDJ9, 3, 3震荡区间买卖点MACD12, 26, 9大级别方向判断实操中我的经验是先用 MACD 判断方向和是否在零轴上方再用 ZLSMA 判断价格是否站上趋势线最后用 KDJ 找具体入场点。三者共振时信号质量最高但共振次数很少所以实际策略里我会给每个指标分配不同权重而不是要求全部满足。最后说一个我踩过几次坑的体会技术指标本身不复杂复杂的是数据口径。同样一个 MACD你用不同数据源、不同复权方式算出来的信号可能完全不同。所以做量化第一步永远是先把数据链路摸透。Tushare 这套前复权加指标计算的流程我在本地跑了快两年稳定性和一致性都让我比较放心。你把它作为一个基础数据层沉淀下来后面接任何策略逻辑都不用再回过头折腾数据和指标口径的问题了。本文还有配套的精品资源点击获取
返回列表