ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

用Python量化分析A股:行情数据获取与异常波动识别

2026/9/3 3:44:04 拓冰建站 浏览量
用Python量化分析A股:行情数据获取与异常波动识别 很多股民在看到“A股跳水”“主力狂卖600亿”这类新闻时第一反应是找消息、打听内幕、看别人怎么操作。但如果你是一个技术人员换个角度想行情剧烈波动的背后其实是一堆可以被量化、被监控、被可视化的数据。新闻标题负责调动情绪而数据接口和代码负责还原事实。这篇文章不预测涨跌也不提供任何操作建议。我要做的事情是把“异常跳水”“主力资金流出”这类模糊的盘面说法拆解成 Python 可以处理的数据字段和计算指标。读完你会得到一个能跑的行情数据获取方案、一个异常波动识别工具以及一套主力资金流向分析脚本。以后市场再出现类似波动你可以自己拉数据、跑指标而不是只看标题。需要先说明白一点本文所有内容仅供技术学习与量化研究使用不构成任何投资建议。市场有风险决策请独立思考。1. 这篇文章真正要解决什么问题打开任何一个行情软件你会看到价格、成交量、振幅、换手率、资金流向等几十个字段。但大多数人只盯着红绿数字看忽略了这些字段背后可以用来做量化分析的结构化逻辑。当大盘出现快速下跌时技术层面真正值得关注的问题有三个第一怎样用数据定义一个“异常波动”。是跌幅超过某个阈值还是成交量突然放大还是振幅拉大如果标准不统一不同人说的“跳水”根本不是同一个概念。第二怎样获取一份可靠、可复现的数据。很多散户的消息来源是社交媒体截图而技术方案应该直接对接数据接口把日K线、分时、资金流等数据拉下来存成结构化文件。第三怎样把“主力资金卖出”这种说法可视化。资金流向的统计口径是什么主力净流出是怎么算出来的如果不理解口径看任何资金排名都可能被误导。这篇文章适合三类读者正在学习 Python 数据分析想找个真实场景练手的开发者对量化交易感兴趣想知道行情数据从哪里来、怎么清洗、怎么计算指标的初学者被新闻标题搞得焦虑、想用技术手段还原盘面信息的投资者。你不需要有金融背景。只要会基础的 Python 语法跟着文章敲完代码就能得到一套可运行的行情分析小工具。2. 核心概念行情字段、资金流向与异常波动指标在动手写代码之前先把几个核心概念讲清楚。这些概念在行情软件里很常见但很多人其实不知道每个字段背后的计算逻辑。2.1 日K线核心字段开盘价Open交易日第一笔成交的价格。收盘价Close交易日最后一笔成交的价格。最高价High日内最高成交价格。最低价Low日内最低成交价格。成交量Volume当日成交的总股数或总手数。成交额Amount当日成交的总金额。这四个价格字段组合在一起就构成了一根K线。收盘价相对前一日收盘价的涨跌幅就是我们常说的“今天涨了还是跌了”。2.2 主力资金流向“主力资金”并不是一个精确的交易所定义而是行情服务商根据单笔成交量大小所做的一种划分。常见的分法是把订单分成超大单、大单、中单、小单其中超大单和大单被近似视为主力资金。主力净流入的计算方式大致是主力净流入 主力买入金额 - 主力卖出金额如果结果是正数说明从该口径看大资金整体在买如果是负数就说明大资金整体在卖。这也是“主力狂卖600亿”这类新闻背后的数据来源。需要注意的是不同平台对“大单”的划分门槛不同。有的按单笔金额大于20万元算大单有的按100万元算。所以当你看到两个app显示的主力净流入数值不一致时不用太奇怪大概率是统计口径不同。2.3 异常波动识别指标识别异常波动通常要同时看价格和成交量两个维度涨跌幅当日收盘价相对前日收盘价的变化比例。振幅(最高价 - 最低价) / 前日收盘价反映日内价格波动范围。量比当日每分钟平均成交量与过去5日每分钟平均成交量的比值。量比大于1说明放量小于1说明缩量。当跌幅较大、振幅较宽、量比显著放大同时出现时从技术指标上就可以认定为一次典型的“异常跳水”。这套逻辑完全可以用代码实现。3. 环境准备与数据源选型本文使用 Python 实现核心依赖是pandas数据清洗与分析akshare免费开源的中国金融数据接口无需注册token即可使用大部分功能matplotlib绘制K线、成交量和资金流向图。建议使用 Python 3.8 及以上版本。包管理工具使用 pip。pip install akshare pandas matplotlib如果你的网络环境下载较慢可以指定国内镜像源pip install akshare pandas matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple这里特别说明一下数据源选型。目前国内常用的行情数据接口主要有两类akshare免费、无需token、接口覆盖股票、基金、期货、宏观数据等适合个人学习和研究tushare需要注册并获取token积分越高可调用的接口越全适合对数据稳定性要求更高的场景。本文以 akshare 为例因为它的上手门槛最低。如果你的项目需要更高频率的数据或更稳定的接口可以再评估 tushare 或专业行情服务商。4. 获取A股日线行情数据我们先用 akshare 获取一只股票的日线数据。以平安银行股票代码 000001为例示例代码如下# 文件路径fetch_stock_data.py import akshare as ak import pandas as pd def fetch_daily_data(symbol: str, start_date: str, end_date: str) - pd.DataFrame: 获取A股日线行情数据 :param symbol: 股票代码如 000001 :param start_date: 开始日期格式 20240101 :param end_date: 结束日期格式 20240814 :return: DataFrame df ak.stock_zh_a_hist( symbolsymbol, perioddaily, start_datestart_date, end_dateend_date, adjustqfq # 前复权 ) return df if __name__ __main__: df fetch_daily_data(000001, 20240101, 20240814) print(df.head()) print(df.tail())代码说明adjustqfq表示前复权。复权是为了剔除分红送股对价格的影响让历史价格具有可比性。接口返回的字段包括日期、股票代码、开盘、收盘、最高、最低、成交量、成交额、振幅、涨跌幅、涨跌额、换手率。如果你只想分析大盘指数而不是个股可以把接口换成大盘指数日线import akshare as ak # 上证指数符号为 sh000001 df_index ak.stock_zh_index_daily(symbolsh000001) print(df_index.tail())运行后你会看到上证指数从发布到当前日期的日线数据字段包括 date、open、high、low、close、volume。大盘数据适合用来观察“A股跳水”这类全市场级别的波动而个股数据适合分析具体标的。5. 异常波动识别如何用数据定义“跳水”拿到日线数据之后下一步是计算异常波动指标。我们不使用任何主观判断而是通过阈值规则来识别当日跌幅小于等于 -2%视为较大下跌振幅大于等于 5%说明日内分歧剧烈当日成交量相对过去5日的平均成交量放大约1.5倍以上视为放量。三个条件同时满足时标记为一次“异常波动信号”。# 文件路径anomaly_detector.py import akshare as ak import pandas as pd def load_data(symbol: str 000001): df ak.stock_zh_a_hist( symbolsymbol, perioddaily, start_date20240101, end_date20240814, adjustqfq ) # 统一列名便于后续计算 df.rename(columns{ 日期: date, 开盘: open, 收盘: close, 最高: high, 最低: low, 成交量: volume, 涨跌幅: pct_chg, 振幅: amplitude }, inplaceTrue) return df def add_anomaly_flag(df: pd.DataFrame) - pd.DataFrame: # 计算量比当日成交量 / 过去5日平均成交量 df[vol_ma5] df[volume].rolling(window5).mean() df[volume_ratio] df[volume] / df[vol_ma5] # 异常波动条件 df[is_anomaly] ( (df[pct_chg] -2.0) (df[amplitude] 5.0) (df[volume_ratio] 1.5) ) return df if __name__ __main__: df load_data() df add_anomaly_flag(df) # 输出所有被标记为异常波动的日期 anomaly_days df[df[is_anomaly] True] print(anomaly_days[[date, close, pct_chg, amplitude, volume_ratio]])这段代码的核心是使用 pandas 的rolling函数计算滚动均值。rolling(window5).mean()表示取当前行及之前4行的平均值用来衡量“最近5天平均成交量”。当某一天的成交量明显高于这5天均值时volume_ratio就会显著大于1。需要提醒的是阈值不是固定的。不同的市场环境、不同的个股适合的参数可能完全不同。在实际项目中阈值应该做成配置项而不是写死在代码里。这样后续调整时只需要改配置不需要动逻辑代码。6. 主力资金流向分析价格和成交量是结果而资金流向是很多人用来解释“结果为什么会这样”的依据。akshare 提供了现成的个股资金流向接口我们可以直接使用。# 文件路径fund_flow.py import akshare as ak import pandas as pd def fetch_fund_flow(symbol: str 000001, market: str sz): 获取个股资金流向数据 :param symbol: 股票代码 :param market: 市场sz表示深圳sh表示上海 df ak.stock_individual_fund_flow( stocksymbol, marketmarket ) return df if __name__ __main__: df fetch_fund_flow(000001, sz) print(df.tail(10))接口返回的主要字段包括日期收盘价涨跌幅主力净流入净额主力净流入净占比超大单净流入净额大单净流入净额中单净流入净额小单净流入净额。如果只是想看全市场主力资金的总流出量可以通过大盘资金流向接口获取import akshare as ak df_market ak.stock_market_fund_flow() print(df_market.tail())这个接口返回的字段通常包括日期、上证/深证涨跌幅、主力净流入额等。所谓“主力狂卖600亿”在数据上就对应这些字段的负值累加。这里要特别强调口径问题。不同平台对主力资金的判定标准不同。akshare 返回的数据来自其数据源和某些行情软件上显示的数字可能不一致。所以实战中不要只盯一个数值而应该同时看净流入、净占比、超大单变化等多个字段并且要清楚自己用的是哪一套口径。7. 可视化把跳水和资金流向画出来数据算完之后文字输出不够直观。我们用 matplotlib 画两张图一张是收盘价和成交量的组合图另一张是主力净流入的柱状图。# 文件路径visualize.py import matplotlib.pyplot as plt import akshare as ak import pandas as pd plt.rcParams[font.sans-serif] [SimHei] # 解决中文乱码 plt.rcParams[axes.unicode_minus] False # 解决负号显示问题 def load_data(symbol: str 000001): df ak.stock_zh_a_hist( symbolsymbol, perioddaily, start_date20240601, end_date20240814, adjustqfq ) df.rename(columns{ 日期: date, 收盘: close, 成交量: volume }, inplaceTrue) df[date] pd.to_datetime(df[date]) return df def plot_price_volume(df: pd.DataFrame): fig, ax1 plt.subplots(figsize(12, 6)) ax1.plot(df[date], df[close], colorred, linewidth1.5, label收盘价) ax1.set_ylabel(收盘价) ax1.legend(locupper left) ax2 ax1.twinx() ax2.bar(df[date], df[volume], alpha0.3, colorgray, label成交量) ax2.set_ylabel(成交量) ax2.legend(locupper right) plt.title(A股个股价格与成交量走势) plt.show() if __name__ __main__: df load_data() plot_price_volume(df)资金流向可视化也一样简单。假设我们已经从资金流向接口拿到了“主力净流入净额”字段可以用柱状图来展示每天主力净流入为正还是为负import matplotlib.pyplot as plt import akshare as ak df_flow ak.stock_individual_fund_flow(stock000001, marketsz) df_flow[日期] pd.to_datetime(df_flow[日期]) colors [red if x 0 else green for x in df_flow[主力净流入净额]] plt.figure(figsize(12, 6)) plt.bar(df_flow[日期], df_flow[主力净流入净额], colorcolors, alpha0.7) plt.axhline(0, colorblack, linewidth0.8) plt.title(个股主力资金净流入) plt.xlabel(日期) plt.ylabel(主力净流入净额) plt.show()为什么要用两种颜色因为在A股中“红涨绿跌”是国内软件的习惯用法。主力净流入为正时用红色为负时用绿色符合国内用户认知。 matplotlib 默认颜色含义可能和国内习惯相反这里我们手动指定颜色来保证可读性。8. 异常波动监控写一个简单的信号扫描器前面的步骤都是针对单只股票或指数。实战中你会希望一次性扫描多只股票找出哪些标的出现了异常波动信号。这里给出一个简单的扫描器思路。# 文件路径scanner.py import akshare as ak import pandas as pd def scan_anomaly(symbols, start_date20240701, end_date20240814): results [] for symbol in symbols: try: df ak.stock_zh_a_hist( symbolsymbol, perioddaily, start_datestart_date, end_dateend_date, adjustqfq ) if df.empty: continue df.rename(columns{ 日期: date, 收盘: close, 成交量: volume, 涨跌幅: pct_chg, 振幅: amplitude }, inplaceTrue) df[vol_ma5] df[volume].rolling(5).mean() df[volume_ratio] df[volume] / df[vol_ma5] df[is_anomaly] ( (df[pct_chg] -2.0) (df[amplitude] 5.0) (df[volume_ratio] 1.5) ) hit df[df[is_anomaly] True] if not hit.empty: for _, row in hit.iterrows(): results.append({ symbol: symbol, date: row[date], close: row[close], pct_chg: row[pct_chg], amplitude: row[amplitude], volume_ratio: round(row[volume_ratio], 2) }) except Exception as e: print(f[{symbol}] 处理失败: {e}) continue return pd.DataFrame(results) if __name__ __main__: stock_list [000001, 000002, 600519, 000858, 300750] result scan_anomaly(stock_list) if not result.empty: print(result) else: print(扫描完成未发现满足条件的异常波动信号。)这个扫描器有几个工程细节值得注意每次请求之间不需要强制 sleep但如果你扫描的股票数量很多建议加上time.sleep(0.5)或更长的时间避免触发接口限流。try-except是必要的。单只股票数据拉取失败不应该导致整个扫描中断。这个版本用的是同步循环。如果扫描几百只股票耗时较长可以考虑用线程池优化但要先确认接口是否允许高并发。9. 常见问题与排查思路实际运行过程中你可能会遇到下面这些问题。我把常见的情况整理成了一张表问题现象可能原因排查方式解决方案安装 akshare 失败网络连接超时或依赖冲突查看 pip 错误日志使用国内镜像源或创建独立的虚拟环境安装中文图表乱码系统缺少中文字体打印 matplotlib 字体列表确认当前字体安装中文字体或指定SimHei、Microsoft YaHei接口返回数据为空股票代码错误或日期区间无交易检查股票代码是否带有前缀、日期是否合理核对代码扩大日期范围验证资金流向数据缺失接口升级或字段变动打印 df.columns 查看返回字段以实际接口返回为准调整列名映射量比计算结果为 NaN前几行 rolling 窗口不足检查数据是否有足够的历史记录数据量过少时放弃该信号或扩大数据范围多线程请求被限制访问过于频繁触发反爬策略观察是否出现连接失败或响应超时增加 sleep 时间降低并发数这里最值得提醒的是接口字段变动问题。免费的第三方数据接口字段名和接口名都可能随版本升级而变化所以代码里做rename时最好先打印df.columns看一眼真实字段名避免硬编码导致运行报错。10. 工程实践建议把脚本变成可复用的分析流程如果你不只是跑一次玩玩而是想把这些脚本变成日常可复用的工具下面几条工程建议值得听。第一封装数据层和策略层。把数据获取统一封装成一个类比如DataSource提供get_daily(symbol, start, end)和get_fund_flow(symbol)方法。指标计算和信号判断放在另一个模块里。这样数据源变了只需要改数据层不影响策略逻辑。第二做好本地缓存。每次启动脚本都重新请求历史数据很浪费接口配额也很慢。推荐第一次拉取后保存为 CSV 或 Parquet 文件后续只增量拉取最新数据。import pandas as pd import os CACHE_FILE daily_cache.csv def load_with_cache(symbol000001): if os.path.exists(CACHE_FILE): df pd.read_csv(CACHE_FILE) else: df ak.stock_zh_a_hist(symbolsymbol, perioddaily, start_date20240101, end_date20240814, adjustqfq) df.to_csv(CACHE_FILE, indexFalse) return df第三信号结果需要留痕。无论是异常波动信号还是资金流信号都应该在产生时保存一份带时间戳的记录。这样事后可以复盘这个信号是什么时候触发的当时的市场环境是什么样后续行情怎么走的。没有留痕的量化研究很难迭代。第四回测意识要从第一天开始建立。很多人在写监控脚本时只关注“现在发出什么信号”却忽略了“这个信号历史上有没有用”。建议把信号产生的日期、当时的指标值、后续3天或5天的涨跌幅都记录下来累积一段时间后做统计分析再判断阈值是否合理。11. 数据接口的边界与合规提醒最后必须把风险和边界问题讲透。第一免费数据接口主要用于个人学习和研究不适合直接部署在面向生产环境的服务上。如果你要做一个正式的量化分析系统应该评估专业数据服务商购买合规的数据授权。第二不要用爬虫手段频繁请求任何网站或接口。代码里做好请求频率控制尊重数据来源的服务器资源。第三技术分析只是研究市场的一种方式它不能预测未来。我可以用代码计算出历史上每一次“放量下跌”之后平均走势如何但这不保证下一次还会重复同样的规律。任何打着“技术指标包赚”旗号的言论都违背了概率统计的基本常识。第四本文涉及的代码只做数据计算和可视化不包含任何下单、交易或自动化买卖功能。本文也不构成投资建议。如果你要做实盘交易请务必使用券商官方提供的API并在充分了解风险的前提下操作。12. 总结与下一步实践建议这篇文章做了一件很具体的事把一个带有强烈情绪色彩的金融新闻标题拆解成了可以被 Python 处理的行情数据字段和量化指标。你跟着代码跑通了日线数据获取、异常波动识别、资金流向分析和可视化得到了一套完全属于你自己的盘中监控工具雏形。下一步建议你按三个方向去深入一是数据维度扩展。可以尝试接入分时数据、盘口数据、公告数据看看异常波动前后是否有其他可观测的信号二是指标体系优化。现在的异常判断只用了跌幅、振幅、量比三个维度。你可以加入换手率、资金净占比、指数联动性等指标构建更细的评分模型三是回测研究。把历史数据拉长到3年或5年统计分析你的信号在过去几年的胜率和盈亏比然后再决定是否值得继续迭代。最后再说一句数据接口会更新、阈值会调整、市场环境会变化但“用数据还原事实、用代码验证判断”这套方法论是长期有效的。希望这篇文章能让你在看行情时多一个技术视角。