Python获取港股实时行情实战:腾讯接口解析与监控工具开发
2026/9/17 10:48:25 网站建设 项目流程

开盘前五分钟,我还在忙着把昨晚整理好的候选股清单导入脚本,今天想做的是在盘中实时盯一下港股的异动。写了个几十行的小工具,直接打印腾讯行情接口返回的最新价、涨跌幅、成交量,同样时间,那些手动刷新网页的同事还在挨个翻行情。这篇博文就是围绕“用 Python 获取实时港股行情数据”这件事,从接口选型、环境准备、代码实现到问题排查做一个完整复盘。

如果你是个刚接触 Python 的投资者,或者想尝试把行情数据接进自己的量化/提醒系统,这篇文章会帮你少踩不少坑。腾讯和新浪有公开的港股实时行情接口,不需要付费开通数据终端就能拿到分钟级甚至更快的报价,而且 Python 处理这类 HTTP 请求 + 字符串解析非常顺手。我会把背后关于接口字段、请求头、时区判断这些容易被忽略的细节全部展开,所有代码都是可以直接复制跑通的。

1. 项目背景与方案选型

1.1 需求拆解:你到底要什么行情

很多人一上来就问“怎么获取港股实时行情”,但实际场景差别很大。有人只是盯几只看好的股票,需要简单的最新价和涨跌幅;有人想监控持仓、在个股异动时自动弹窗提醒;还有人希望把行情存到数据库里供后续分析。需求不同,技术方案的侧重点完全不一样。

我自己这次的目标很明确:用最小成本拿到港股实时报价,包括最新价、今日开盘、最高最低、成交量、成交额、买卖盘口这些基础字段,然后做两个应用——一个命令行下实时刷新的迷你看板,一个简单的价格波动提醒。这里的关键词是“稳定”和“免费”,所以我优先考虑公开 HTTP 接口,而不是去向券商申请专门的行情网关。港股实时数据在交易所层面是要收费的,但市面上不少门户网站为了展示行情,自己购买了数据授权后提供了公开的 HTTP 端口,通过模拟浏览器请求就能拿到接近实时的快照。我的方案就是基于这类接口搭建。

还要说清楚一个概念:实时不等于 tick-by-tick 逐笔成交。对绝大多数个人投资者来说,获取到秒级或分钟级的快照已经足够。所谓“实时行情”,在免费接口的语境下通常指延迟在几秒到十几秒内的最新报价快照,而非 Level-2 的逐笔委托流。如果你的策略真的要求交易所原始行情,那就得走正规的行情服务商渠道,这不在本文讨论范围。

1.2 为什么选择腾讯接口作为主力数据源

国内开发者获取港股行情,绕不开腾讯和新浪这两个公开接口。我最终选择腾讯接口作为主力,原因其实很实在。

先说新浪。新浪的hq.sinajs.cn接口返回数据非常简洁,一条字符串搞定,但有个坑:必须带上Referer: https://finance.sina.com.cn这个请求头,否则会返回403 Forbidden。腾讯的qt.gtimg.cn接口相对“宽容”一些,直接 GET 就能返回,而且字段比新浪更丰富,包含了多个维度的买卖五档、总市值、市盈率等扩展信息。对于做行情快照和数据解析来说,腾讯更顺手。

腾讯接口的 URL 格式大概是:

https://qt.gtimg.cn/q=hk00700, hk09988

q=后面跟股票代码,多个代码用英文逗号分隔。港股代码统一使用hk前缀 + 五位数字。注意腾讯的港股代码一直是五位,像腾讯控股是00700,不能写成0700700,少了前导零接口会返回空数据。这一点前面调试时踩过坑,后面会专门说。

返回内容是一段类似v_hk00700="200~腾讯控股~00700~..."的字符串,字段用~分隔。整个响应的处理逻辑非常直接,不需要 JSON 解析,用split("~")就能把关键字段取出来。对于 Python 这种字符串处理方便的语言来说,简直是无脑操作。

1.3 数据时效、频率限制和合规边界

使用这类免费接口,需要先搞清楚它的时效和限制。实测下来,腾讯港股接口返回的数据在交易时段内大概是几秒更新一次,做日常盯盘完全没问题。但它不是官方交易数据流,不要指望它用来做毫秒级的高频策略,也不应该把它当成成交量统计的权威来源。

关于调用频率,这个接口没有明确公布阈值,但以我们的经验,常规的单机脚本每秒请求一次,持续几个小时是没有问题的。如果多人共用同一出口 IP 高频抓取,可能会被临时限流,表现就是返回空字符串或者v_pv_none_match="1"。后面第 4 章我会讲遇到限流后怎么处理。

合规方面也需要说两句。公开门户接口用于个人学习、研究和非商业用途,是行业内大家默认的玩法;但如果你想把数据打包出售、提供商业行情服务,或者在证券相关业务中作为正式数据源,那必须购买授权,否则会面临版权和数据服务条款的问题。我的做法是只在个人脚本和自用工具中使用,不对外分发原始数据,遇到盘口数据只取来辅助判断,不做二次传播。这条底线建议读者也守住。

2. 开发环境与基础准备

2.1 Python 环境安装与依赖库

起步阶段假设你的电脑没有 Python。国内用户建议直接到 Python 官网下载对应系统的安装包,安装时记得勾选Add Python to PATH,否则后面命令行里输入 python 会提示找不到命令。Linux 用户则可以用包管理器安装,比如 Ubuntu 上的sudo apt install python3 python3-pip

装好 Python 之后,打开终端验证一下:

python --version

如果能正确输出版本号,说明环境配置成功。我建议使用 Python 3.8 以上的版本,后面代码会用到类型注解和 f-string 等特性,太老的版本跑起来会报错。

接下来安装第三方库。这个项目实际上只需要一个标准库就可以完成,连 requests 都未必用得上,因为腾讯接口用urllib.request就能请求。不过为了代码更简洁、处理超时更方便,我还是习惯装一下requests

pip install requests

如果下载慢,把 pip 源切换成国内镜像:

pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple

除了 requests,后面做数据可视化的时候还会用到 matplotlib,做数据表格处理会用到 pandas。这些可以等实际需要时再装,不必一开始就把环境搞得臃肿。我的原则是“用到哪个装哪个”,因为每个人扩展的方向不一样。

2.2 核心请求头与接口调试技巧

腾讯接口虽然不需要 Referer,但为了更接近真实浏览器行为,建议还是加上User-Agent。有些部署在网络层面做了比较严格的检查,伪造一个浏览器的 UA 能减少被拦截的概率。

我们先用 curl 或者直接在 Python 里做一个一次性验证,看看接口到底返回什么格式。建议刚开始调试时不要批量请求,先取一只股票:

import requests url = "https://qt.gtimg.cn/q=hk00700" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" } resp = requests.get(url, headers=headers, timeout=5) resp.encoding = "gbk" # 关键:接口返回的是GBK编码 print(resp.text)

这里要特别注意resp.encoding = "gbk"。腾讯接口返回的数据是 GBK 编码,如果不设置的话,requests 大概率会把它识别成 ISO-8859-1,中文股票名会直接乱码。这是新手最容易踩的坑之一。

运行之后,预期会看到类似这样的一长串:

v_hk00700="200~腾讯控股~00700~386.800~386.800~387.200~...";

其中以~分隔的每个位置都有固定含义。我的做法是先把它解析成列表,然后打印前几个字段对照一下,不用硬记序号。如果你对每个字段含义好奇,后面第 3 章会给出常见字段对照表。

2.3 代码结构规划

这个项目虽然小,但为了避免逻辑纠缠,我建议按功能拆成三个部分:

  • 数据获取模块:负责拼接 URL、发送请求、返回股票代码对应的原始文本。
  • 数据解析模块:把原始字符串按~拆开,转换成字典结构。
  • 应用层:负责展示、监控或其它业务逻辑。

这样做的目的是方便后续扩展。今天你可能只做命令行看板,明天想加个网页展示,后天想把它接进钉钉/企业微信机器人,如果解析层复用得好,这些都是改几行代码的事。

我们先按照“先跑通、再优化”的思路。第一版可以全部写在一个.py文件里,但请在注释里标记清楚边界。这篇文章后面给出的代码,都尽量保留这种分层思路,让你能直接照着抄。

3. 获取行情数据的完整实现

3.1 单只股票的实时行情获取

先从最简单的开始,写一个函数获取单只股票行情并解析成字典。

import requests import json def get_quote_hk(symbol: str) -> dict: """ 获取港股实时行情快照 :param symbol: 港股代码,如 "00700",必须带前导零 :return: 解析后的行情字典 """ # 统一转为标准五位数代码 code = f"hk{symbol}" url = f"https://qt.gtimg.cn/q={code}" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" } resp = requests.get(url, headers=headers, timeout=5) resp.encoding = "gbk" text = resp.text.strip() if "=" not in text: return {} # 提取等号后面的内容,去掉分号和首尾引号 payload = text.split("=", 1)[1].strip().strip(";").strip('"') # 按 ~ 拆分字段 fields = payload.split("~") # 根据腾讯接口字段顺序,组装常用字段 quote = { "symbol": fields[2] if len(fields) > 2 else symbol, "name": fields[1] if len(fields) > 1 else "", "price": float(fields[3]) if fields[3] else 0.0, "prev_close": float(fields[4]) if fields[4] else 0.0, "open": float(fields[5]) if fields[5] else 0.0, "volume": int(fields[6]) if fields[6] else 0, "high": float(fields[33]) if len(fields) > 33 and fields[33] else 0.0, "low": float(fields[34]) if len(fields) > 34 and fields[34] else 0.0, "change": float(fields[31]) if len(fields) > 31 and fields[31] else 0.0, "change_percent": float(fields[32]) if len(fields) > 32 and fields[32] else 0.0, "amount": float(fields[37]) if len(fields) > 37 and fields[37] else 0.0, } return quote if __name__ == "__main__": data = get_quote_hk("00700") print(json.dumps(data, ensure_ascii=False, indent=2))

这段代码有几个地方需要重点说明。

第一,code = f"hk{symbol}"那里,如果传入的是700,拼出来就是hk700,腾讯接口会找不到股票。所以我建议调用方必须传五位数字。也可以在函数内部强制格式化:

code = f"hk{symbol:0>5}"

这样即使你传入700,它也能自动补全为hk00700。但这个补全逻辑只适用于五位以内的代码,如果传入123456就不合适了。实际使用时建议统一在数据源维护五位代码。

第二,字段位置的编号不是顺序排列的。比如最高价highfields[33],最低价lowfields[34],涨跌额在fields[31],涨跌幅在fields[32]。这不是我拍脑袋写的,而是通过打印完整列表后对应出来的。腾讯接口的字段很丰富,但 unfortunately 官方并没有文档明说每个下标含义,所以只能靠经验整理。下面我列一下经过多次验证的常用字段对照表。

下标含义示例
0未知/固定标识200
1股票名称腾讯控股
2股票代码00700
3最新价386.800
4昨收价386.800
5今开价387.200
6成交量(手)1234567
31涨跌额3.400
32涨跌幅0.88
33最高价388.400
34最低价383.600
37成交额(元)476532123
38换手率0.12
39市盈率12.34

需要说明的是,volume在第 6 个字段,但腾讯对港股的成交量单位一般是“手”,一手可能等于 100 股(具体看股票)。这个细节我在做成交量对比时专门验证过,如果你计算出成交量明显少了一个数量级,大概率是单位换算的问题。

第三,为什么代码里对fields[3]这类位置要做空字符串判断?因为当股票代码不存在或者停牌时,接口可能返回空字段。如果直接float("")会抛异常,所以写了个三元表达式判断。实际项目中可以直接封装一个_safe_float函数,让代码更整洁:

def _safe_float(value, default=0.0): try: return float(value) except (ValueError, TypeError): return default

等到数据源跑起来,你会发现安全转换函数几乎是必须的——接口偶尔给你返回"--"或者空串,这都很正常。

3.2 批量获取多只股票数据

实时盯盘只看一只股票肯定不够,更常见的需求是同时监控十几只。腾讯接口支持一次查询多个代码,用逗号分隔即可。比如:

https://qt.gtimg.cn/q=hk00700,hk09988,hk03690

批量请求的好处很明显:减少 HTTP 连接次数,速度快很多,也能降低被限流的风险。我们把上面的单只代码扩展一下,写一个批量函数。

import requests def get_quotes_hk(symbols: list) -> dict: """ 批量获取港股行情 :param symbols: 港股代码列表,如 ["00700", "09988"] :return: {symbol: quote_dict} """ if not symbols: return {} # 统一转为标准五位代码 normalized = [] for s in symbols: s = s.strip() if not s.isdigit(): raise ValueError(f"Invalid symbol: {s}") normalized.append(f"hk{s:0>5}") url = "https://qt.gtimg.cn/q=" + ",".join(normalized) headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" } resp = requests.get(url, headers=headers, timeout=5) resp.encoding = "gbk" result = {} # 返回的文本可能有多行,每行对应一只股票 for line in resp.text.strip().split(";"): line = line.strip() if not line: continue if "=" not in line: continue var_part, payload_part = line.split("=", 1) # 从 v_hk00700 中提取股票代码 var_name = var_part.strip() code = var_name.replace("v_hk", "").replace("_quote", "").strip() payload = payload_part.strip().strip('"') fields = payload.split("~") quote = { "symbol": code, "name": fields[1] if len(fields) > 1 else "", "price": float(fields[3]) if len(fields) > 3 and fields[3] else 0.0, "prev_close": float(fields[4]) if len(fields) > 4 and fields[4] else 0.0, "open": float(fields[5]) if len(fields) > 5 and fields[5] else 0.0, "volume": float(fields[6]) if len(fields) > 6 and fields[6] else 0.0, "high": float(fields[33]) if len(fields) > 33 and fields[33] else 0.0, "low": float(fields[34]) if len(fields) > 34 and fields[34] else 0.0, "change_percent": float(fields[32]) if len(fields) > 32 and fields[32] else 0.0, } result[code] = quote return result

上面这段代码里,我用了var_name来提取股票代码。你可能会想:为什么不直接从fields[2]取代码?确实,fields[2]是接口返回的股票代码,但它可能包含前导零,也可能因为某些股票的特殊代码而不同。从变量名提取会更稳定,因为这个变量的格式是腾讯接口固定的,就是v_hk加上你请求时的代码。

批量请求的一个注意点是返回文本顺序不一定跟请求顺序完全一致。我测试过多次,腾讯一般会按请求顺序返回,但为了稳妥,建议把结果存成字典而不是列表,用代码做 key。这样即使顺序有变,也不影响使用。

3.3 实时报价的数据结构再深入

有些读者会问:腾讯接口返回的数据里包含了买卖五档,也就是 Level-1 常见的盘口快照。确实,虽然腾讯是免费接口,但它在某些字段里提供了五档买卖报价。下面是五档对应的下标,我列出来作为参考:

下标含义
9买一量(手)
10买一价
11买二量
12买二价
13买三量
14买三价
15买四量
16买四价
17买五量
18买五价
19卖一量
20卖一价
21卖二量
22卖二价
23卖三量
24卖三价
25卖四量
26卖四价
27卖五量
28卖五价

如果你要做盘口异动监控,可以直接从这些下标取值。不过要记住,这里面的量单位同样是“手”,别把它当成股。另外,港股的价格最小变动单位跟股票价格区间有关,比如低价股可能是 0.001,高价股可能是 0.2,在做价格档位判断时要注意这一点。

我实际使用中一般只用到最新价、涨跌幅和成交量,盘口数据用得比较少,因为免费接口的盘口更新有延迟,对手盘判断的参考价值有限。如果你想拿它做盘口深度分析,最好跟券商交易软件上的盘口对比一下,心里有数再决定是否依赖。

3.4 实现一个命令行实时看板

光有函数还不够,为了实用,我写了一个简单的命令行看板,可以每隔几秒刷新一次,同时展示多只股票。Linux 和 macOS 用的清屏指令是clear,Windows 用的是cls,代码里做一个跨平台处理。

import os import time import requests def get_quotes_hk(symbols): # 这里直接复用上面的批量函数,省略重复代码 pass def clear_screen(): os.system("cls" if os.name == "nt" else "clear") def format_board(symbols): quotes = get_quotes_hk(symbols) lines = [] header = f"{'代码':<8}{'名称':<10}{'最新价':>10}{'涨跌幅':>10}{'成交量(手)':>14}" lines.append(header) lines.append("-" * len(header)) for sym, q in quotes.items(): name = q["name"] price = q["price"] pct = q["change_percent"] vol = q["volume"] # 涨跌幅显示带正负号 pct_str = f"{pct:+.2f}%" lines.append(f"{sym:<8}{name:<10}{price:>10.3f}{pct_str:>10}{vol:>14,.0f}") return "\n".join(lines) if __name__ == "__main__": watchlist = ["00700", "09988", "03690", "01810", "02020"] while True: clear_screen() print("港股实时行情 - Ctrl+C 退出") print() try: print(format_board(watchlist)) except Exception as e: print(f"获取失败: {e}") # 每5秒刷新一次 time.sleep(5)

这段代码的效果是,终端会每隔 5 秒刷新一次表格。你可以把它放在桌面角落,边做别的事边瞥一眼。如果不想用轮询的方式断点续跑,也可以把while True改成循环固定次数,或者用计划任务在特定时间段运行。

这里有个小技巧:刷新频率没必要太激进。免费接口的数据几秒才会更新一次,如果你 1 秒刷一次,可能看到的价格和上次一样,白白消耗请求次数。5 秒是比较合理的间隔。如果你想监控更快的变化,可以把高频请求只集中在少数几只有异动的股票上,而不是全市场扫描。

3.5 将行情数据继续处理:画图和存储

有时候纯文字不够直观。比如我想看某只股票今天的日内走势,但腾讯这个行情接口只返回快照,并不包含分时数据。那怎么办?一个折中方案是:自己定时采集数据,把点连成线。虽然不是交易所官方分时,但至少能记录我们关注时段的价格变化。

我们可以在循环里把每次取到的price和时间戳追加到列表,退出时写到 CSV 文件。下面是一个简单示例:

import csv import time from datetime import datetime # 假设已经定义好 get_quote_hk def collect_to_csv(symbol, duration_seconds=3600, interval=10): start = time.time() rows = [] while time.time() - start < duration_seconds: q = get_quote_hk(symbol) if q: row = { "ts": datetime.now().isoformat(timespec="seconds"), "price": q["price"], "volume": q["volume"], } rows.append(row) print(row) time.sleep(interval) if rows: with open(f"{symbol}_quotes.csv", "w", newline="", encoding="utf-8") as f: writer = csv.DictWriter(f, fieldnames=["ts", "price", "volume"]) writer.writeheader() writer.writerows(rows)

采集完 CSV 之后,用 pandas + matplotlib 画图就非常简单了:

import pandas as pd import matplotlib.pyplot as plt df = pd.read_csv("00700_quotes.csv") df["ts"] = pd.to_datetime(df["ts"]) plt.figure(figsize=(10, 5)) plt.plot(df["ts"], df["price"]) plt.title("00700 intraday price snapshot") plt.xlabel("time") plt.ylabel("price") plt.grid(True) plt.show()

这种自建数据积累的方式虽然土,但对个人研究完全够用。积累几周后,你就可以做简单的成交量分布分析,或者对比不同股票在同一时段的波动率。当然,如果你想要历史全量日线数据,分时拼接肯定不行,那就需要去拉历史K线接口,这是另一个话题了。

4. 常见问题与排查技巧实录

4.1 返回数据为空或乱码的排查

这个是最常见的问题。空数据通常有几个原因:

一是股票代码格式不对。港股代码必须是五位,且带hk前缀。我见过hk0700700.HK00700.HK各种写法,腾讯接口只认hk00700这一种。建议在代码里做一次严格格式化,不接受用户随便输入。

二是接口请求失败被限制。你可以先手动在浏览器地址栏访问https://qt.gtimg.cn/q=hk00700,如果浏览器能正常显示一长串字符,说明接口本身没问题,那就是脚本里的请求头或者代理设置问题。requests.get可能走了系统代理,如果代理不可用就会超时。可以显式设置proxies={}proxies={"http": None, "https": None}避免代理干扰。

三是编码问题。乱码的根源前面已经说了,就是编码没有指定 GBK。有一种更稳妥的写法:

resp.raw.decode_content = True

但这不影响文本解码。最直接的办法还是resp.encoding = "gbk",如果你拿到的还是乱码,可以打印resp.encoding看看它到底用的什么编码。

4.2 请求频率过高被限流的表现和应对

如果你写了个 for 循环,把几千只股票拆成几百个请求,高频循环去抓,就可能遇到以下返回内容:

v_pv_none_match="1";

或者干脆返回一个空字符串。这就说明你的出口 IP 被临时限制了。遇到这个情况,最简单的做法是等下再试,同时降低请求频率。更合理的做法是设计重试机制:

import time def safe_request(url, headers, max_retry=3): for i in range(max_retry): try: resp = requests.get(url, headers=headers, timeout=5) if resp.text.strip(): return resp except requests.RequestException: pass time.sleep(min(2 ** i, 10)) return None

指数退避重试是标准做法,刚开始失败就等 1 秒,再失败等 2 秒、4 秒,最多等 10 秒。这样可以避免在服务端还没恢复时持续猛打。另外,尽量把多只股票合成一个请求,几十上百只也就一个请求搞定,自然不会频繁触发限制。

4.3 交易时间与时区判断

港股交易时间比较特别,除了早市、午市,还有早盘前的竞价时段。简单判断“现在能不能交易”至少要包含这几种情况:

  • 周末:周六、周日休市。

  • 节假日:香港公众假期和内地不完全一致,比如圣诞节港股休市,内地不放假。如果脚本要靠系统日期做判断,得维护一个节假日列表,或者干脆不判断,让脚本一直请求,反正接口在休市时返回的也是昨收数据,不会报错。

  • 盘中:港股连续竞价时段是 9:30-12:00、13:00-16:00,还有 16:00-16:10 的收市竞价。提前五分钟进场拿到的可能是静默期的快照,价格基本不动,但这也没问题。

在代码里做交易时段判断,需要注意时区。如果你的服务器是美国时区或者 UTC,直接用datetime.now()判断会出现大偏差。建议强制用香港时区:

from datetime import datetime, timezone, timedelta hkt = timezone(timedelta(hours=8)) now_hk = datetime.now(hkt)

然后把now_hk的小时和分钟拿去判断。我见过有人直接在本地跑,结果人在中国,时区没问题,但部署到云服务器后定时任务全乱套了。统一用timezone(timedelta(hours=8))是最稳妥的。

4.4 接口偶尔延迟与数据源切换方案

腾讯接口虽然总体稳定,但也偶尔会出现几秒的延迟,某些时候甚至超过 10 秒。这可能是网络链路问题,也可能是接口服务繁忙。为了增加可靠性,我习惯在代码里留一个“备胎”。

新浪接口作为备用,请求格式如下:

https://hq.sinajs.cn/list=hf_HK00700

注意新浪港股代码格式是hf_HK+ 五位数字,且需要带Referer。如果你已经用了腾讯,不一定需要真的切换过去,但在设计函数时把数据源抽象出来,做成可配置的:

data_source = "tencent" # 或 "sina" def get_quote(symbol): if data_source == "tencent": return get_quote_tencent(symbol) elif data_source == "sina": return get_quote_sina(symbol)

这样一旦腾讯接口暂时不可用,手动改一个变量就能切换。我的建议是不要轻易在运行时自动切换,因为两个接口字段含义并不完全一致,容易产生数据口径混淆。人工切换更安全。

另外一个小问题:腾讯接口返回的股票名称可能是繁体中文。如果你后续做股票名匹配,建议统一转成简体,或者直接用代码做 key,不要用中文名做唯一标识。

4.5 关键细节:涨跌幅计算与复权问题

腾讯接口直接提供了涨跌幅字段,在fields[32]。如果你要用它来判断异动,那没问题。但如果你决定自己算(用最新价对比昨收价),要注意港股可能因拆股、合股、派息导致昨收价出现调整,单纯用“现在价格/昨收-1”算出来的涨跌幅跟行情软件显示的不完全一致。所以在绝大多数场景下,直接用接口给出的涨跌幅字段更省心,它已经处理了权益调整。

还有一个细节是浮点精度。港股价格精确到小数点后三位,但接口返回的某些字段用了字符串"386.800",转成float是 386.8,展示时想保留三位小数,记得用格式化字符串f"{price:.3f}"

5. 自动化监控与后续扩展建议

5.1 如何做一个价格异动提醒

行情数据接到手以后,最实用的玩法之一就是价格提醒。比如你想在腾讯控股涨幅超过 2% 时收到通知,可以写一个简单的轮询脚本。关键不是复杂的算法,而是如何合理地触发通知。

最简单的方式是启动一个常驻进程,每隔 10 秒或 30 秒获取一次行情,检查条件,满足时推送通知到手机。通知渠道可以使用 Server 酱、钉钉机器人、企业微信机器人、邮件等。这里给一个钉钉机器人的简化示例:

import requests import time def send_dingtalk(message): webhook = "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN" payload = { "msgtype": "text", "text": {"content": message} } requests.post(webhook, json=payload) def monitor(symbol, threshold=2.0, interval=30): while True: q = get_quote_hk(symbol) if q and q["change_percent"] >= threshold: msg = f"{q['name']}({q['symbol']}) 涨幅 {q['change_percent']:.2f}%,现价 {q['price']:.3f}" send_dingtalk(msg) # 发送后避免频繁轰炸,等到涨幅回调后重新触发 while True: time.sleep(interval) q2 = get_quote_hk(symbol) if q2["change_percent"] < threshold - 0.5: break time.sleep(interval)

这里有个很关键的工程细节:如果不加“重新触发”逻辑,价格只要还在阈值以上,脚本就会每 30 秒给你发一条消息,非常烦人。我上面的设计是:触发后进入“等待”循环,直到涨幅回落到阈值以下 0.5 个百分点,才解除警报,避免重复提醒。你可以根据自己的需要调整回落幅度。

5.2 数据落库与基础统计

如果你想把行情存储起来做长期分析,CSV 是一个起步方案,但查询不太方便。更进阶的做法是把数据写入 SQLite,Python 内置 sqlite3 模块,无需额外安装。我写过一个小例子:

import sqlite3 from datetime import datetime conn = sqlite3.connect("hkoverse.db") conn.execute(""" CREATE TABLE IF NOT EXISTS quotes ( symbol TEXT, name TEXT, price REAL, change_percent REAL, volume REAL, ts TEXT ) """) def insert_quote(q, ts=None): ts = ts or datetime.now().isoformat(timespec="seconds") conn.execute("INSERT INTO quotes VALUES (?,?,?,?,?,?)", (q["symbol"], q["name"], q["price"], q["change_percent"], q["volume"], ts)) conn.commit()

有了 SQLite 之后,你可以按天、按周查询某只股票的价格轨迹,也可以结合 Python 的 pandas 做进一步分析。当然,长时间高频采集会导致数据库体积膨胀,所以建议每隔一段时间清理冗余数据,或者按月份分表。个人使用的话,SQLite 完全够用,不值得为了这个项目专门上 MySQL。

5.3 从快照到日线:历史数据补全思路

有时候我们需要的历史数据不是自己一段段采,而是直接拉过去几年的日线。腾讯和新浪也有历史K线的接口,但返回格式比较复杂,且不是公开文档化的稳定接口。如果你追求稳定且轻量,更推荐直接使用一些开源财经数据包,比如akshareakshare封装了大量公开数据源,包含港股历史行情,接口相对稳定,适合个人研究。

使用方式很简单:

import akshare as ak # 获取港股历史日线 df = ak.stock_hk_daily(symbol="00700", adjust="qfq") print(df.tail())

不过要提醒一句,akshare本质上也是爬取各家网站数据,同样存在接口失效的风险。依赖它没问题,但版本更新要跟上,遇到报错时先升级到最新版本再排查。我在使用中一大半的akshare报错都是因为版本太旧,数据源网站调整之后旧版就不兼容了。

5.4 把脚本部署到服务器定时运行

如果你的电脑不会一直开着,可以考虑把采集脚本部署到一台低配置的云服务器或 NAS 上,配合 crontab 或 systemd timer 定时跑。部署到 Linux 服务器时,建议用venv创建虚拟环境,避免污染系统 Python。

示例 crontab:

*/5 9-16 * * 1-5 cd /path/to/project && /usr/bin/python3 collector.py >> logs/collector.log 2>&1

上面这个表达式表示周一至周五的 9 点到 16 点之间,每 5 分钟执行一次采集脚本。注意这是服务器本地时间,如果服务器时区不是东八区,要先把 crontab 的时区调整了,或者脚本内部自行判断。另一个替代方案是写一个长期运行的 Python 进程,配合schedule库做定时任务,但 crontab 更简单,进程崩了也会被系统自动拉起,前提是脚本自身有良好的日志输出。

说到日志,我强烈建议任何长期运行的脚本都加上日志记录。简单的方式是:

import logging logging.basicConfig( filename="hquotes.log", level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s" )

这样即使某个时间点数据源异常,你也可以事后回溯,而不是面对黑屏毫无头绪。

6. 复盘与个人经验补充

写到这里,整个“用 Python 获取实时港股行情数据”的核心内容基本讲完了。最后再分享一段个人体会。

我最初做这个项目时,注意力全放在“怎么把数据拉下来”,但实际过程中花费时间最多的反而是那些看起来微不足道的小问题:GBK 编码、前导零、成交量单位、时区、限流重试。如果你也准备自己动手做,建议别急着写大段复杂的逻辑,先把单只股票的接口跑通,把每一行返回内容打印出来看一遍,再逐步增加批量、展示和提醒功能。

关于数据准确性的问题,我必须坦白:免费接口的数据偶尔会跟券商软件有细微差异,尤其在成交量、盘口这些时变性很强的字段上。所以不要拿它作为交易决策的唯一依据。我自己的习惯是把它用于“发现问题”,比如一支股票突然放量大涨,脚本提醒我,我再打开正式交易软件做二次确认。这种场景下,免费接口的性价比已经足够高了。

接下来你还可以尝试把行情数据接入 pandas,做成策略回测;或者用它做同一板块股票的联动分析。思路打开之后,这个小小的接口能帮你省下大量手动刷网页的时间。如果你在跑代码时遇到任何跟本文不一致的表现,建议先从版本差异和接口变化两个角度排查——这类免费接口没有长期稳定不变的服务保障,学会快速适应变化,才是长期能用的关键。

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

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

立即咨询