☰
通达信策略Python量化选股框架:从公式复刻到多因子回测实战
2026/9/30 1:21:06 网站建设 项目流程

简介:这份资源是一套基于通达信策略的Python量化选股框架,面向具备一定Python基础、希望把通达信选股思路落地为可运行代码的量化投资者与策略研究者,用于解决选股逻辑分散、难以批量回测与统一管理的问题。压缩包共111个文件,约211KB,以73个py源码文件为核心,辅以13个pyc编译文件、8个sh脚本、4个xml与4个md说明文档,另有txt、json、iml、example、template等配置与模板文件,整体结构清晰,便于按模块阅读与二次开发。内容涵盖数据管理、API配置、项目知识总结与更新说明等模块,读者可据此理解选股框架的组织方式,参考数据获取、策略编写与配置管理的实现思路,并借助示例与模板快速搭建自己的量化选股流程。目前已有62人学习下载,适合作为量化选股入门与框架搭建的实践参考。

1. 拆开这个通达信策略 + Python 量化选股框架,我看到了什么

很多人做量化选股,卡在第一步不是策略本身,而是数据从哪来、怎么把通达信里那套熟悉的指标逻辑搬到 Python 里跑。这个资源包给的就是一条现成的路子:用 Python 搭一套量化选股框架,把通达信策略的思路复刻进去,形成可回测、可批量扫描、可输出选股结果的系统。它适合两类人——一类是手里有通达信指标源码、想批量验证选股效果的实战派;另一类是想学 Python 量化交易、但不想从零造轮子的入门者。核心价值在于把「通达信公式」和「Python 选股引擎」这两件事接上了,省掉大量数据清洗和框架搭建的重复劳动。

2. 环境搭建与数据接入:让 Python 先能读到行情

2.1 为什么选 Python 而不是继续用通达信公式

通达信公式语言(TDX)在盘中预警、副图指标上确实快,但它有两个硬伤:一是回测能力弱,想跑十年历史数据验证一个选股逻辑,公式语言几乎做不了;二是无法做组合筛选,比如「同时满足 RPS 强度 + 主力追踪 + 缠论买点」的多条件交集,公式里写起来又长又难维护。Python 的优势正好补这两块——pandas 处理时间序列、numpy 做向量化计算、backtrader 或自建回测循环验证策略,还能把选股结果直接写进 Excel 或数据库。

这个框架的定位不是替代通达信,而是把通达信里验证过的指标逻辑「翻译」成 Python 能跑的形式。常见做法是:先在通达信里用副图指标确认信号形态,再把公式里的核心条件(比如均线排列、量比阈值、RPS 排名)用 pandas 重写,最后跑全市场扫描。

2.2 环境配置:Python 安装与依赖库

新手最容易翻车的地方就是环境。我一般建议用 conda 建独立环境,避免和系统 Python 打架。下面是可抄作业的步骤:

# 创建独立环境,Python 版本建议 3.9 或 3.10,兼容性最好 conda create -n tdx_quant python=3.10 conda activate tdx_quant # 核心依赖:数据处理 + 回测 + 行情接口 pip install pandas numpy matplotlib pip install akshare baostock # 免费行情数据源,适合日线级选股 pip install openpyxl xlsxwriter # 选股结果写 Excel pip install tushare # 如有积分可用,数据更全

逻辑说明:akshare 和 baostock 是两个不需要付费就能拿到 A 股日线数据的库,适合做选股框架的数据底座。tushare 数据质量更高但需要积分,按需选装。openpyxl 和 xlsxwriter 用于把每日选股结果导出成 Excel,方便盘中对照通达信看盘。

参数说明:Python 版本不要选 3.12 以上,部分量化库还没适配;akshare 接口偶尔会因为数据源调整而失效,建议同时装 baostock 做备份。

2.3 行情数据获取与本地存储

数据接入是选股框架的命脉。这个资源包的核心思路是「本地缓存 + 增量更新」,避免每次选股都全量拉数据。

import akshare as ak import pandas as pd import os from datetime import datetime, timedelta # 本地数据目录 DATA_DIR = "./stock_data" os.makedirs(DATA_DIR, exist_ok=True) def fetch_daily_data(symbol, start_date="20200101"): """获取单只股票日线数据,带本地缓存""" file_path = os.path.join(DATA_DIR, f"{symbol}.csv") # 如果本地已有数据,只增量拉取最新部分 if os.path.exists(file_path): existing = pd.read_csv(file_path, parse_dates=["date"]) last_date = existing["date"].max().strftime("%Y%m%d") # 从上次日期往后拉 new_data = ak.stock_zh_a_hist( symbol=symbol, period="daily", start_date=last_date, adjust="qfq" ) if not new_data.empty: combined = pd.concat([existing, new_data]).drop_duplicates( subset=["date"], keep="last" ) combined.to_csv(file_path, index=False) return combined return existing else: # 首次全量拉取 df = ak.stock_zh_a_hist( symbol=symbol, period="daily", start_date=start_date, adjust="qfq" ) df.to_csv(file_path, index=False) return df # 示例:拉取单只股票 df = fetch_daily_data("000001") print(df.tail())

逻辑说明:adjust="qfq"表示前复权,量化选股必须用复权数据,否则除权除息日会出现假信号。增量更新逻辑是先读本地 CSV 的最后日期,只拉之后的数据再合并去重,这样每天更新全市场 5000 只股票也就几分钟。

参数说明:start_date根据回测需求设定,一般至少拉 3 年数据才有统计意义。symbol是 6 位代码,akshare 的stock_zh_a_hist接口返回的列包括日期、开盘、收盘、最高、最低、成交量、成交额等,够大部分选股因子用。

注意:akshare 接口有频率限制,批量拉取时建议加time.sleep(0.3),否则容易被限流。全市场首次拉取建议分批次,别一次性跑 5000 只。

3. 通达信指标逻辑的 Python 复刻:从公式到因子

3.1 均线系统与 RPS 强度因子的实现

通达信里最常见的选股条件就是均线多头排列和 RPS(相对价格强度)。RPS 的本质是个股在全体股票中的涨幅排名百分位,通达信里用EXTDATA或自定义板块实现,Python 里用 pandas 的rank一行搞定。

import pandas as pd import numpy as np def calc_ma(df, periods=[5, 10, 20, 60]): """计算多条均线""" for p in periods: df[f"ma{p}"] = df["收盘"].rolling(window=p).mean() return df def calc_rps(close_matrix, window=20): """ 计算 RPS 相对强度 close_matrix: 列为股票代码,行为日期的收盘价矩阵 window: 计算涨幅的周期,默认 20 日 """ # 计算每只股票 window 日涨幅 returns = close_matrix.pct_change(periods=window) # 取最新一天的涨幅,做百分位排名 latest_returns = returns.iloc[-1] rps = latest_returns.rank(pct=True) * 100 return rps # 假设已有全市场收盘价矩阵 close_df # close_df = pd.DataFrame(...) # index=日期, columns=股票代码 # rps_series = calc_rps(close_df, window=20) # strong_stocks = rps_series[rps_series > 90].index.tolist()

逻辑说明:pct_change(periods=window)算的是 N 日涨幅,rank(pct=True)把涨幅转成 0 到 1 的百分位,乘 100 就是 RPS 值。RPS > 90 意味着这只股票在过去 20 天里涨幅排进全市场前 10%,这是欧奈尔 CANSLIM 体系里的核心过滤条件。

参数说明:window一般取 20、50、120 三个周期分别算 RPS,短周期抓爆发、长周期抓趋势。均线周期 5/10/20/60 是 A 股常用的组合,60 日线常被当作中期趋势分水岭。

3.2 量价配合与主力追踪信号的翻译

通达信里「主力追踪」类副图指标,核心逻辑通常是「放量突破 + 资金流入」。Python 里可以用成交额和价格变化的关系来近似。

def volume_breakout(df, vol_ratio_threshold=2.0, price_change_threshold=0.03): """ 量价突破信号 vol_ratio_threshold: 量比阈值,当日成交量 / 5日均量 price_change_threshold: 当日涨幅阈值 """ df["vol_ma5"] = df["成交量"].rolling(5).mean() df["vol_ratio"] = df["成交量"] / df["vol_ma5"] df["pct_change"] = df["收盘"].pct_change() # 放量 + 上涨 df["signal"] = ( (df["vol_ratio"] > vol_ratio_threshold) & (df["pct_change"] > price_change_threshold) ) return df # 结合均线过滤:只在 60 日线上方找信号 def filter_by_trend(df): df = calc_ma(df, [60]) df["above_ma60"] = df["收盘"] > df["ma60"] df["final_signal"] = df["signal"] & df["above_ma60"] return df

逻辑说明:量比大于 2 意味着当日成交量是近期均量的两倍以上,配合 3% 以上涨幅,大概率是有资金在主动买入。再加一条「股价在 60 日线上方」的趋势过滤,能过滤掉下跌途中的反弹假信号。

参数说明:vol_ratio_threshold设 2.0 是偏保守的,激进策略可以降到 1.5;price_change_threshold设 0.03 对应 3% 涨幅,如果想抓首板可以调到 0.07 以上。这些参数没有绝对最优,需要根据回测结果调。

3.3 多因子组合与选股结果输出

单因子选股噪音大,实战里一般是多因子打分。这个框架的思路是:每个因子给一个分数,加权求和后取 Top N。

def multi_factor_score(df, rps_value, ma_signal, vol_signal): """ 多因子打分 rps_value: RPS 值 0-100 ma_signal: 均线多头排列 bool vol_signal: 量价突破 bool """ score = 0 score += rps_value * 0.4 # RPS 权重 40% score += 30 if ma_signal else 0 # 均线信号 30 分 score += 30 if vol_signal else 0 # 量价信号 30 分 return score def export_selection(results, date_str): """导出选股结果到 Excel""" output_path = f"./selection_{date_str}.xlsx" df = pd.DataFrame(results) df = df.sort_values("score", ascending=False) df.to_excel(output_path, index=False) print(f"选股结果已导出:{output_path},共 {len(df)} 只") return df

逻辑说明:RPS 是连续变量,直接乘权重;均线和量价是布尔信号,满足给固定分。最终按总分排序,取前 20 到 50 只作为候选池。导出 Excel 是为了方便盘中在通达信里对照看 K 线。

参数说明:权重分配可以调整,比如更看重趋势就把均线信号权重提到 40。导出文件名带日期,方便追溯每日选股结果。

4. 避坑与常见问题排查

4.1 数据复权没做对,回测结果全是假的

现象:回测收益曲线漂亮得不像话,实盘一跑就亏。原因:用了不复权数据,除权除息日价格跳空被当成真实涨跌。解决:akshare 拉数据时强制adjust="qfq",baostock 用adjustflag="2"(前复权)。所有价格类因子计算前先确认复权状态。

4.2 未来函数:用当天收盘价选股,却假设当天开盘能买入

现象:选股信号当天涨停,回测显示买入了,但实盘根本买不进。原因:用当日收盘数据算信号,又假设当日能成交,这是典型的未来函数。解决:信号用 T 日收盘数据计算,T+1 日开盘或均价成交。回测时把买入价设为next_open,别用close。

4.3 akshare 接口突然报错或返回空数据

现象:昨天还能拉数据,今天跑就报KeyError或返回空 DataFrame。原因:akshare 底层爬的是公开数据源,对方页面结构一变,接口就失效。解决:先pip install --upgrade akshare升级到最新版;如果还不行,换 baostock 做备份数据源。我一般会在代码里写双数据源切换逻辑,一个挂了自动切另一个。

4.4 全市场扫描太慢,跑一次要半小时

现象:5000 只股票逐个拉数据、算因子,效率极低。原因:没用向量化,循环里反复读文件。解决:先把全市场收盘价和成交量拼成矩阵(index 是日期,columns 是股票代码),因子计算全部用 pandas 向量化操作,比逐只循环快几十倍。数据更新用增量,别每次全量拉。

4.5 选股结果和通达信里看到的不一致

现象:Python 选出来的股票,在通达信里看副图指标并没有信号。原因:通达信公式里可能用了未来函数、或者用了 Python 里没复刻的隐藏条件(比如特定板块过滤、ST 剔除)。解决:逐条对照公式,确认每个条件都翻译到位;特别注意通达信里的REF、BACKSET这类函数,BACKSET是典型未来函数,Python 里不要用。

5. 进阶技巧:用参数扫描找到稳健的因子组合

框架跑通之后,真正决定收益的是参数。我一般不会手动一个个试,而是写一个参数扫描循环,把 RPS 周期、量比阈值、均线周期这几个核心参数做网格搜索,看哪组参数在样本外表现最稳。

import itertools def param_scan(close_matrix, volume_matrix, rps_windows, vol_thresholds): """ 参数网格扫描 返回每组参数对应的选股数量和后续 N 日平均收益 """ results = [] for rps_w, vol_t in itertools.product(rps_windows, vol_thresholds): rps = calc_rps(close_matrix, window=rps_w) selected = rps[rps > 90].index.tolist() # 统计选中股票后续 5 日平均收益 forward_returns = [] for stock in selected: if stock in close_matrix.columns: prices = close_matrix[stock].dropna() if len(prices) > 5: ret = prices.iloc[-1] / prices.iloc[-6] - 1 forward_returns.append(ret) avg_ret = np.mean(forward_returns) if forward_returns else 0 results.append({ "rps_window": rps_w, "vol_threshold": vol_t, "stock_count": len(selected), "avg_forward_5d_return": round(avg_ret, 4) }) return pd.DataFrame(results).sort_values("avg_forward_5d_return", ascending=False) # 示例调用 # scan_result = param_scan(close_df, vol_df, [10, 20, 50], [1.5, 2.0, 2.5]) # print(scan_result.head(10))

逻辑说明:itertools.product做笛卡尔积,遍历所有参数组合。对每组参数,先算 RPS 选出强势股,再统计这些股票后续 5 日的平均收益。收益越高说明这组参数在历史上越有效。注意这只是样本内测试,真正要验证还得留一段样本外数据。

参数说明:rps_windows建议覆盖 10 到 50 日,太短噪音大、太长信号滞后。vol_thresholds从 1.5 到 2.5 足够,再高选不出几只股票。扫描结果按平均收益排序,但别只看收益最高的那组——还要看选股数量,如果只选出 2 只股票,收益再高也没有统计意义。

我自己的习惯是:参数扫描跑完后,把排名前 20 的组合在样本外再跑一遍,只保留样本内外表现一致的参数。那些样本内惊艳、样本外拉胯的组合,基本都是过拟合,实盘会教你做人。从那以后我每次调完参数都强制走一遍样本外验证,再也不敢直接拿样本内最优参数上实盘。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询