news 2026/9/16 1:33:05

抛弃SDK,用cURL直连REST API获取A股行情

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
抛弃SDK,用cURL直连REST API获取A股行情

做量化分析或者自己写选股工具的人,最烦的一件事就是取数据。A 股行情接口五花八门,大多数服务商上来就丢给你一套 SDK,要求你先装好依赖、配好环境,再写几行初始化代码,最后才能拿到数据。我最初用 AlphaFeed 的时候也按这个套路走了,但用了一段时间之后发现,比起用 SDK,直接拿 cURL 打它的 REST API 反而更省事:不装任何依赖、不绑定编程语言、排查问题也直观得多。这篇文章就把我实际测试整理出来的 HTTP 直连方案完整写出来,适合想快速验证接口、做临时数据拉取,或者需要在 Python、Go、Shell 之间无缝切换的开发者参考。

1. 为什么我抛弃了 SDK,改用 cURL 直连

1.1 SDK 方案的三个痛点

先说清楚,SDK 不是不能用,而是被它绑住之后,你会发现自己陷入一些非常尴尬的处境。

第一是安装依赖的连锁反应。很多行情 SDK 不是孤零零一个包,它会自动拉一堆依赖进来,比如 protobuf、gRPC、websocket 客户端、某些特定版本的 HTTP 库。一套 Python 环境如果同时跑多个数据源,很容易出现 A 的 SDK 要求 requests 2.28,B 的 SDK 要求 requests 2.32,最后你只能靠虚拟环境硬隔离,维护成本直接翻倍。

第二是版本升级的连带伤害。服务商一旦升级 SDK,经常会把接口参数结构也改了,你本地不升级就用不了新功能,升级了旧代码可能直接跑不起来。我遇到过不止一次,官方 SDK 发布新版之后,旧版本的鉴权方式失效,被迫在休息日改代码。

第三是最要命的:SDK 内部封装得太深,出问题你根本不知道它在哪里。返回报错了,你看到的是 SDK 自己定义的异常对象,真正的 HTTP 状态码和响应体被吞掉了,你只能去翻它的源码猜逻辑。而直接用 cURL 打 REST API,整个链路完全透明——请求长什么样、响应长什么样,一眼就能看到底。

1.2 REST API 直连适合谁

REST API 直连方案并不是要完全替代 SDK,而是补充了一个更轻量的选择。我自己的使用场景大致有这么几类:

  • 快速验证一个接口能不能用,写五行业务代码之前先用 cURL 把数据拿回来看看结构;
  • 写一次性脚本拉取历史数据,不想为一个临时任务引入正式依赖;
  • 在服务器上做数据同步,服务器环境干净得像张白纸,cURL 是系统自带的,不用装任何东西;
  • 需要跨语言复用同一套请求逻辑,比如 Shell 脚本负责定时拉取,Python 负责分析,Go 负责展示,大家共用一份 HTTP 接口约定。

本质上,REST API 就是我给你一个 URL,你用标准的 HTTP 方法去访问,服务端返回 JSON 数据。你不需要了解服务端内部怎么实现,只需要会发请求和解析响应,这就够了。SDK 归根结底做的也是同一件事,只不过它在外面包了一层壳。

2. AlphaFeed 接口的入门铺垫

2.1 几个必须搞懂的基础概念

拿到一个 REST API,第一件事不是急着写命令,而是先把四个概念理清楚:Base URL、Endpoint、Query 参数和鉴权头。

Base URL 是服务入口的统一前缀,AlphaFeed 的接口路径一般都挂在类似https://api.alphafeed.com/v1这样的地址下面。Endpoint 是具体资源路径,比如查询实时行情可能是/v1/quote,查 K 线可能是/v1/bars。Query 参数是附加在 URL 问号后面的键值对,用来传递股票代码、周期、时间范围这些条件。鉴权头则是在 HTTP Header 里放你的身份凭证,常见的有X-Api-KeyAuthorization: Bearer这类形式。

把这四个概念搞清楚之后,你会发现不管是哪个数据服务商,接口设计思路都是互通的。今天能看懂 AlphaFeed,明天拿到任何一家新接口,你只需要去它的文档里查一查这四个东西分别是什么,就能立刻上手。

2.2 鉴权方式与请求头设计

AlphaFeed 采用 API Key 的方式鉴权,这也是绝大多数金融数据服务的惯例。你需要在后台申请一个密钥,然后在每个请求的 Header 里带上它,形如:

X-Api-Key: 你的密钥

设计请求头的时候,我建议至少带上这三项,缺一不可:

  • X-Api-Key:身份凭证,服务端靠它识别你是谁;
  • Accept: application/json:明确告诉服务端,你希望返回 JSON 格式;
  • User-Agent:设置一个能标识你的客户端名称,方便服务端做日志追踪。比如User-Agent: my-trading-script/1.0

这里有一个常见误区:很多人以为 POST 请求才需要Content-Type,所以 GET 请求就忽略了。GET 请求确实通常不需要Content-Type,但如果你调的是 POST 类接口(比如批量查询),一定要加上Content-Type: application/json,否则服务端解析不了请求体里的 JSON 数据。

提示:API Key 等同你的账户密码,千万不要硬编码到公开仓库里。建议通过环境变量或者独立的配置文件读取,用完后及时在服务商后台作废回收。

2.3 一次完整请求的生命周期

理解一次完整请求的流转过程,能帮你少走很多弯路。你输入一条 cURL 命令,系统做的大概是这么几步:

  1. 解析 URL,拆出协议、域名、端口和路径;
  2. DNS 解析域名,拿到服务器 IP;
  3. 建立 TCP 连接;
  4. 如果走 HTTPS,则在 TCP 之上完成 TLS 握手;
  5. 按照 HTTP 协议格式,把你的请求行、请求头和请求体发送给服务器;
  6. 服务器处理请求,返回状态码和响应体;
  7. cURL 把响应打印到终端,你看到的就是最终结果。

这一整个过程中,任何一个环节出错都会产生对应的错误提示。比如 DNS 解析失败、TCP 连接被拒绝、TLS 握手失败、服务器返回 5xx,这些错误在 cURL 下的表现形式完全不一样。后面我会专门用一个章节讲这些报错的排查方法,现在你只要记住:先把生命周期里每个环节对应到一条 cURL 报错信息上,排查思路就会清晰很多。

3. cURL 实操:手把手拉取 A 股行情

3.1 环境准备与 cURL 基础参数

cURL 是几乎所有类 Unix 系统的内置工具,Windows 10 以上版本也自带了,不需要额外装。验证一下你的环境里有没有它:

curl --version

看到输出类似curl 8.x.x就说明可以用。如果版本太旧(低于 7.55),建议升级一下,因为后面我要讲的连接复用和并行请求功能在旧版本里表现不佳。

另外强烈建议装一个jq,它是 JSON 数据的瑞士军刀。没有它,你看接口返回只能盯着密密麻麻的 JSON 字符串发呆;有了它,你可以像操作数据库一样精准提取自己想要的那几个字段。

# macOS brew install jq # Debian/Ubuntu sudo apt install jq # CentOS/RHEL sudo yum install jq

3.2 获取实时行情快照

一切就绪之后,我们从最简单的开始:查询一只股票的实时行情快照。以贵州茅台为例,A 股代码在 AlphaFeed 里需要带上交易所后缀,600519.SH表示上交所,000001.SZ表示深交所。

curl -s "https://api.alphafeed.com/v1/quote?symbol=600519.SH" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Accept: application/json"

返回的 JSON 大致长这样:

{ "code": 0, "data": { "symbol": "600519.SH", "name": "贵州茅台", "last": 1688.00, "open": 1670.00, "high": 1695.50, "low": 1662.10, "preClose": 1665.20, "volume": 3200000, "amount": 5400000000, "timestamp": "2025-06-18 15:00:00" } }

终端里直接看这一坨 JSON 眼不眼晕?眼晕就对了,上 jq。如果你想只看收盘价:

curl -s "https://api.alphafeed.com/v1/quote?symbol=600519.SH" \ -H "X-Api-Key: YOUR_API_KEY" | jq '.data.last'

如果你想一次性看多个关键字段,用 jq 的花括号语法构造一个新的 JSON 对象:

curl -s "https://api.alphafeed.com/v1/quote?symbol=600519.SH" \ -H "X-Api-Key: YOUR_API_KEY" | jq '{symbol: .data.symbol, last: .data.last, high: .data.high, low: .data.low}'

这一步做完,你就已经完成了一次标准的 REST API 调用:带鉴权、带参数、拿数据、解析数据。后面的所有操作都是这个流程的变体。

3.3 拉取历史 K 线数据

实时快照只能看当下,要做回测或者趋势分析,必须拉历史 K 线。AlphaFeed 的 K 线接口大致是这样的:

curl -s "https://api.alphafeed.com/v1/bars?symbol=000001.SZ&period=1d&start=2025-01-01&end=2025-06-18&adjust=qfq" \ -H "X-Api-Key: YOUR_API_KEY" | jq '.data[:3]'

这里面有几个参数需要解释一下。

period是 K 线周期,常见取值有1m5m15m30m60m1d1w1M,分别对应分钟线、日线、周线和月线。注意区分大小写,我曾经把1M写成1m,白白等了半天才发现拿到的是分钟线。

adjust是复权方式。做历史回测一定要理解复权的作用:上市公司会分红送股,如果不做复权处理,K 线图上会出现价格跳空,技术指标会被严重扭曲。qfq表示前复权,以最新价格为基准回溯调整历史价格,适合看当前价位下的历史走势;hfq表示后复权,以首日价格为基准,适合计算真实收益率。默认值通常是none,也就是不复权,做短线和只看原始价格的人可以选这个,但做长线回测务必用复权数据。

返回的每条数据包含openhighlowclosevolumeamount和时间戳,结构非常规整,直接转成 DataFrame 或者 CSV 都方便。

3.4 获取分时与逐笔成交数据

分时数据和逐笔成交是两类不同的东西,别搞混。

分时数据通常按分钟聚合,一个时间点只有一条记录,包含这一分钟的均价、成交量等信息,适合看日内走势。请求方式一般是:

curl -s "https://api.alphafeed.com/v1/bars?symbol=600519.SH&period=1m&start=2025-06-18&end=2025-06-18" \ -H "X-Api-Key: YOUR_API_KEY" | jq '.data | length'

jq '.data | length'用来统计返回了多少条数据,这个技巧在验证接口返回完整性的时候非常有用。

逐笔成交则记录了每一笔真实的成交,可能一秒内就有几百条,量级完全不一样。这类接口通常有严格的频率限制和单次返回条数上限,比如每次最多返回 1000 条,需要配合游标分页来拉取完整数据。如果服务商提供了游标参数(常见字段名是cursor或者next_token),记得按文档要求循环请求直到游标为空。

我建议先从小周期 K 线入手,等把整条链路跑通了,再去碰逐笔数据,因为逐笔数据的解析和存储复杂度会高一个量级。

4. 直连 HTTP 的进阶玩法

4.1 公共参数与请求头优化

当你开始频繁调用接口的时候,你会发现每条命令都带一长串-H "X-Api-Key: ..."太啰嗦了。这里有两个优化方向。

第一个方向是使用 cURL 的配置文件。在~/.curlrc或者项目目录下的.curlrc里,可以预设默认请求头:

header = "X-Api-Key: YOUR_API_KEY" header = "Accept: application/json"

这样你再发请求的时候,直接写 URL 就行,cURL 会自动带上配置文件里的 Header:

curl -s "https://api.alphafeed.com/v1/quote?symbol=600519.SH"

简洁了不少,对吧。注意.curlrc的语法是所有参数之间用换行分隔,参数名后面跟空格和值,等号两边没有空格。

第二个方向是善用-G参数。如果你要传的查询参数特别多,直接拼在 URL 后面容易出错,尤其是里面还有特殊字符的时候。用-G配合--data-urlencode,可以让 cURL 自动帮你做 URL 编码:

curl -sG "https://api.alphafeed.com/v1/bars" \ --data-urlencode "symbol=600519.SH" \ --data-urlencode "period=1d" \ --data-urlencode "start=2025-01-01" \ --data-urlencode "end=2025-06-18" \ --data-urlencode "adjust=qfq"

如果你要查询的股票名称里带着中文或者特殊符号,这个方式能帮你避免很多编码折磨。

4.2 返回数据结构与字段解读

很多人拿到接口返回之后,不做任何加工就直接塞进分析程序里,这是不对的。REST API 的返回数据通常有统一的包装结构,AlphaFeed 的设计类似这样:

{ "code": 0, "message": "success", "data": { ... } }

code是业务状态码,0表示正常,非零值对应各种业务错误;message是对状态的辅助说明;data是真正的数据体。所以写任何处理脚本,第一判断应该是检查code是否为 0,而不是直接去取data

这里有一个踩坑点:HTTP 状态码和业务状态码是两回事。HTTP 200 只代表请求被服务器正常处理了,不代表业务逻辑成功。比如你查询一只不存在的股票代码,服务器可能会返回 HTTP 200,但code是 10001,message写着 "symbol not found"。如果你的脚本只检查了 HTTP 状态码,就会把错误数据当成正常数据拿去分析,结果可想而知。

正确的处理逻辑是:先看 HTTP 状态码判断网络层有没有问题,再看code判断业务层有没有问题,两层都通过了,才去解析data

4.3 频率控制、连接复用与超时设置

行情数据接口最忌讳的就是不加控制地疯狂请求。AlphaFeed 的免费额度通常有频率限制,比如每分钟最多 60 次请求,超出后返回429 Too Many Requests,同时响应头里会带Retry-After字段,告诉你要等多少秒才能继续。

批量拉取多只股票的时候,很多人会写一个循环,每次请求都新建连接,这是非常低效的。HTTP 连接建立的成本很高,尤其是 HTTPS 还需要 TLS 握手。好在 cURL 对连接复用有自动处理:当你把多个 URL 放在同一条命令里时,如果它们指向同一个服务器,cURL 会自动复用连接。

curl -s "https://api.alphafeed.com/v1/quote?symbol=600519.SH" \ "https://api.alphafeed.com/v1/quote?symbol=000001.SZ" \ "https://api.alphafeed.com/v1/quote?symbol=601318.SH" \ "https://api.alphafeed.com/v1/quote?symbol=600036.SH"

查看-v输出,如果看到Re-using existing connection字样,就说明连接复用生效了。这一条命令相比多次单独调用,能省掉大量握手开销。

超时设置同样重要,没有设置超时的请求可能会卡住几分钟甚至更久。两个关键参数:

  • --connect-timeout 10:建立连接的超时时间,设 10 秒足够;
  • --max-time 30:整个请求的最大耗时,包含数据传输时间。

这两个参数务必加到你的命令里,尤其是写进 crontab 定时任务的时候。没有超时限制的任务一旦卡住,会一直占着你的进程和内存,甚至影响服务器上的其他业务。

如果需要更高并发,可以用 curl 7.66 以上版本提供的--parallel系列参数。--parallel 8表示同时最多发送 8 个请求,配合--parallel-immediate可以在请求列表还没完全生成时就启动发送,拉取几百只股票的行情时效率提升非常明显。

5. 常见报错与排查实录

5.1 HTTP 状态码速查

我在实际调试过程中,最常遇到的状态码就这么几个,整理成一张表方便你直接对照。

状态码含义常见原因处理方式
400 Bad Request请求参数错误参数缺失、格式不对、股票代码不带交易所后缀检查 URL 参数,对照文档逐项核对
401 Unauthorized鉴权失败API Key 没传、传错了、密钥已过期检查请求头里的X-Api-Key
403 Forbidden无权访问IP 不在白名单、账户权限不够去后台设置里加上当前 IP
404 Not Found路径不存在Endpoint 拼错了、版本号不对检查路径是否匹配文档
429 Too Many Requests触发频率限制请求太密集读取Retry-After响应头,等够时间再请求
500 Internal Server Error服务端内部错误服务商自己的问题稍后重试,或者报工单
502 Bad Gateway网关错误服务商上游服务异常退避重试,比如等 1 秒、2 秒、4 秒递增
524 A Timeout Occurred网关超时请求处理太久,服务器还没返回缩小查询范围,或者改用分页拉取

5.2 我踩过的几个坑

第一个坑是 cURL 的错误码 3,提示URL rejected: Port number was not a decimal number。我第一次看到这个报错完全懵了,因为我根本没写端口号。后来发现问题是 URL 里某个参数值带了冒号,比如时间字符串2025-06-18T00:00:00没有做 URL 编码,cURL 把冒号后面的内容误认为是端口号了。解决办法很简单:用--data-urlencode传参数,或者把冒号改成%3A

第二个坑是错误码 35,TLS 握手失败。这个通常在服务器时钟不准、或者本机根证书过期的时候出现。排查思路是先确认系统时间是否正确,再尝试更新根证书:

sudo apt install ca-certificates

第三个坑是 502 和 524 交替出现。有一段时间我写了一个批量脚本,每次拉 2000 只股票的日线,跑着跑着就报502 Bad Gateway。一开始我以为是服务商挂了,后来发现是我一次性请求的数据量太大,服务端处理超过了网关的超时限制,被上游断开了。解决方式是把大请求拆成小批量,每次只查 50 只股票,配合连接复用和退避重试,问题就消失了。

第四个坑是频率限制的误判。我当时以为只要每次请求间隔大于 1 秒就不会触发 429,结果还是一直被限流。后来仔细看文档才发现,AlphaFeed 的限流是按窗口计算的,比如 5 分钟窗口内最多 300 次请求,不是按简单的每秒速率。要妥善应对这种情况,你得在代码里维护一个请求时间戳队列,每次发请求前先检查窗口内已经发了多少次,预判是否会触限。

5.3 从 cURL 平滑迁移到脚本批量拉取

cURL 适合快速验证接口和使用原始 HTTP 逻辑,但当你确认这套直连方案可行,需要每天定时拉数据的时候,把它写进脚本会更靠谱。我最常用的两个方案是 Shell 循环和 Python requests。

Shell 方案适合轻量任务,比如每天收盘后拉取全市场日线:

#!/bin/bash symbols=$(cat symbols.txt) for s in $symbols; do curl -sG "https://api.alphafeed.com/v1/bars" \ --data-urlencode "symbol=$s" \ --data-urlencode "period=1d" \ --data-urlencode "adjust=qfq" \ --connect-timeout 10 \ --max-time 30 >> bars.jsonl sleep 0.5 done

这里把每次请求的结果以 JSON Lines 格式追加写入文件,每行一个 JSON 对象,后续用 jq 或者 Python 做流式解析都很方便。

Python 方案适合需要重试和错误处理的复杂任务。注意,换语言不等于换思路,本质上你还是在对同一个 REST API 发 HTTP 请求,只是把 cURL 换成了 requests 库:

import time import requests def fetch_bars(symbol, api_key): url = "https://api.alphafeed.com/v1/bars" params = {"symbol": symbol, "period": "1d", "adjust": "qfq"} headers = {"X-Api-Key": api_key, "Accept": "application/json"} for attempt in range(5): resp = requests.get(url, params=params, headers=headers, timeout=30) if resp.status_code == 200 and resp.json().get("code") == 0: return resp.json()["data"] if resp.status_code == 429: time.sleep(int(resp.headers.get("Retry-After", 60))) elif resp.status_code >= 500: time.sleep(2 ** attempt) else: break return None

这段代码里有两个设计细节值得说一下。超时设置timeout=30对应 cURL 的--max-time,防止请求卡死;重试用了指数退避2 ** attempt,第一次失败等 1 秒,第二次等 2 秒,第三次等 4 秒,这样既不会把服务商打崩,也能在临时故障恢复后自动续上。

最后再分享一个我在实际项目中常用的技巧:任何脚本落地之前,先拿 cURL 把要调的每个接口手动跑一遍,确认参数和返回结构都对,再转换成代码。这一步看起来多花了十分钟,实际上能帮你省下未来好几个小时的排错时间。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 1:32:23

Qt/C++实现B样条曲线:de Boor算法与节点向量详解

简介:这是一套基于C与QT的B样条曲线绘制工程,面向CAD、计算机图形学及机械设计方向的开发者和学习者,可在Windows、Linux等平台直接构建运行,用于生成与交互调整平滑样条曲线,支持控制点拖拽、实时更新等操作。压缩包内…

作者头像 李华
网站建设 2026/9/16 1:32:16

CS5530+STM32G070高精度ADC驱动实战:SPI时序与滤波校准

简介:面向STM32嵌入式开发者的一套CS5530驱动与硬件集成资料包,适用于需要通过STM32G070微控制器与CS5530芯片进行数据采集、通信控制的物联网、仪器仪表及工业控制场景。压缩包共3个文件,包含2个C语言源文件与1份PDF原理图说明,整…

作者头像 李华
网站建设 2026/9/16 1:32:08

STM32F103标准库UART串口通信实验详解:从初始化到中断接收

简介:面向嵌入式开发初学者,这是一份基于STM32F103C8T6芯片的UART串口通信标准库实验工程,通过串口输入1、2或3触发不同输出,直观演示串口初始化、参数配置以及数据收发等完整流程。工程在Keil环境下可直接编译下载,适…

作者头像 李华
网站建设 2026/9/16 1:29:31

麒麟Kylin V10系统yum源更换教程:从阿里云到本地源全攻略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/16 1:29:25

Linux上安装RustFS:DEB与RPM包完整实战指南

在 Linux 上装一个软件,听起来好像不是什么大事,下载、解压、运行,三步走完。可一旦这个软件是存储组件,是要塞进生产环境长期跑下去的,事情就没那么简单了。最近我在帮团队评估 RustFS,准备把它作为对象存…

作者头像 李华
网站建设 2026/9/16 1:29:17

用MATLAB构建海底地形模型:坐标提取、插值与重采样全流程

简介:面向涉海专业课程设计与毕业设计的MATLAB海底地形模拟器小型源码包,适合具备基础MATLAB操作经验、希望快速搭建水下地形三维仿真原型的读者。资源共6个文件,以4个M脚本为核心,分别承担地图坐标提取、分辨率转换、地形生成与主…

作者头像 李华