作为量化交易探索系列的第一篇,先解决”数据从哪来”的问题。选型上直接锁定 AKShare——纯 Python 库、覆盖 A 股/港股/美股/期货/期权/基金/宏观数据、一行代码返回 pandas DataFrame,接口密度和文档完备度在开源界里是最高的一档。它自己不产生数据,而是把东方财富、新浪财经、各大交易所官网的公开数据抓取清洗后统一封装,学术研究或者个人策略研发场景都够用了。
这篇文章不是”教程搬运”,而是我在 MacBook M5 上完整跑一遍从环境搭建到拿到数据的实录,包括中间遇到的每一个坑和排查思路。目标读者:想在自己 Mac 上跑起来数据接口的开发者。
Table of contents
Open Table of contents
环境规划
先明确要装什么、装到哪:
- Python 3.13:AKShare 官方要求 3.9+,我用 Homebrew 装的 3.13(本文成稿时的最新稳定版)
- 虚拟环境 venv:所有依赖只装到
~/venvs/akshare里,不污染系统 Python - akshare 本体:从 PyPI 安装,走标准
pip install
这里有个反直觉的点值得先说清楚:要用 AKShare 不需要 clone 它的 GitHub 仓库。pip install akshare 会把打包好的源码放到 venv 的 site-packages/ 下,Python 从那里 import。clone 仓库只在两种情况下有用:想改源码提 PR,或者用 pip install -e 做可编辑安装。绝大多数使用者跳过 clone 这一步。
一、装 Python 与创建 venv
macOS 自带的 /usr/bin/python3 通常是老版本(Python 3.9.6)而且链接的是 LibreSSL,urllib3 v2 会警告不兼容。用 Homebrew 装个新版更省事:
brew install python@3.13
装完确认路径:
which python3.13
# 一般是 /opt/homebrew/bin/python3.13 或 /opt/homebrew/opt/python@3.13/bin/python3.13
创建一个专门给 akshare 用的虚拟环境:
python3.13 -m venv ~/venvs/akshare
source ~/venvs/akshare/bin/activate
激活成功后终端提示符会变成 (akshare) ~。
关于 venv 有个概念要理清楚:venv 只是”引用”某个 Python 解释器,不会随 Homebrew 升级自动联动。也就是说 ~/venvs/akshare 是用 Python 3.13.14 建的,以后不管你 brew upgrade 到 3.14 还是 3.15,这个 venv 会一直用 3.13.14,除非你 rm -rf 掉重新 python3.14 -m venv 建一个。这个特性其实是优点——不同项目可以固定在特定 Python 版本上,不会因为系统升级而莫名其妙报错。
二、安装 akshare
激活 venv 之后直接装:
pip install akshare --upgrade
如果在国内网络下走阿里云镜像更快:
pip install akshare -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host=mirrors.aliyun.com --upgrade
验证装好了:
python3 -c "import akshare; print(akshare.__version__)"
# 输出 1.18.64(或更新版本)
三、第一次跑数据:中招的坑
用官方示例试一下拉平安银行日线:
import akshare as ak
df = ak.stock_zh_a_hist(
symbol="000001",
period="daily",
start_date="20240101",
end_date="20241231",
adjust="",
)
print(df)
结果一片红:
requests.exceptions.ProxyError:
HTTPSConnectionPool(host='push2his.eastmoney.com', port=443):
Max retries exceeded with url: /api/qt/stock/kline/get?...
(Caused by ProxyError('Unable to connect to proxy',
RemoteDisconnected('Remote end closed connection without response')))
关键词是 ProxyError——意味着请求被送到某个代理去了,但代理连不上。
四、排查代理配置
env | grep -i proxy
# http_proxy=http://127.0.0.1:6864
# https_proxy=http://127.0.0.1:6864
我常年开着科学上网类工具,它勾选了”设置为系统代理”,同时也把代理环境变量写进了 ~/.zshrc。问题是 push2his.eastmoney.com 是国内网站,本来应该直连,被代理转发反而适得其反——境外出口 IP 会被东方财富的风控直接掐掉连接。
4.1 临时验证:curl 观察实际发生了什么
curl -v https://push2his.eastmoney.com/api/qt/stock/kline/get
输出的关键几行:
* Uses proxy env variable https_proxy == 'http://127.0.0.1:6864'
* Connected to 127.0.0.1 (127.0.0.1) port 6864
* CONNECT tunnel established, response 200
* SSL connection using TLSv1.3
> GET /api/qt/stock/kline/get HTTP/1.1
* Empty reply from server
curl: (52) Empty reply from server
代理隧道建立成功、TLS 握手也通了,请求发出去之后服务器主动断开、返回空。这就实锤是”经代理走境外 IP 被风控”这条路。
4.2 修复思路:让国内域名直连
有三种方案,按推荐度排:
方案 A(最根本):在代理工具里配”国内直连”规则
Clash 等工具都自带规则集,把模式从”全局”切到”规则”,让 *.eastmoney.com、*.sinajs.cn、*.sina.com.cn 这类国内域名匹配到 DIRECT。这样以后不管什么脚本拉国内数据都不会被代理干扰。
方案 B:给关键域名配 NO_PROXY
不动代理工具,只在 shell 侧告诉 requests:“这几个域名请直连”:
cat >> ~/.zshrc << 'EOF'
# akshare/vnpy 拉国内数据时绕过代理
export no_proxy="eastmoney.com,.eastmoney.com,sina.com.cn,.sina.com.cn,sinajs.cn,.sinajs.cn,127.0.0.1,localhost"
export NO_PROXY="$no_proxy"
EOF
source ~/.zshrc
requests / urllib3 都会读这个变量,效果精确到域名级别,其他流量该走代理还走代理。
方案 C:临时清掉代理变量
unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY
只在当前 shell 生效,新开终端又会被 .zshrc 重新设回。适合一次性测试用,不推荐当作长期方案。
五、再试一次:新的报错,新的方向
按方案 B 配好 NO_PROXY 之后重新跑脚本,代理绕开了(堆栈里没有 ProxyError 字样了),但换成了新错误:
requests.exceptions.ConnectionError:
('Connection aborted.',
RemoteDisconnected('Remote end closed connection without response'))
这次是直连目标服务器,但对方还是主动关断了连接。用 curl 加个浏览器 UA 单独测试:
curl -v --noproxy '*' -A 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) \
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' \
'https://push2his.eastmoney.com/api/qt/stock/kline/get?...'
结果依然是 Empty reply from server。TLS 握手成功、证书验证通过,但服务器看完 HTTP 请求头就断开——这不是 UA 检查那么简单,更可能是东方财富针对境外 IP 或 TLS 指纹(JA3/JA4)的深层风控。
六、绕道解决:换个数据源
AKShare 一个巨大的优点是同一份数据经常有多个实现,走不同的上游数据源。除了 stock_zh_a_hist(东方财富),A 股日线还有:
stock_zh_a_daily(新浪财经)stock_zh_a_hist_pre_min_em(东方财富分钟线)- 各种
_sina/_ths/_ci后缀的实现
新浪那边的接口反爬没这么严格,境外可用。写一个双接口对照的诊断脚本:
# test_akshare.py
import akshare as ak
# 尝试 1:东方财富接口
try:
df = ak.stock_zh_a_hist(
symbol="000001", period="daily",
start_date="20240101", end_date="20241231", adjust="",
)
print("东方财富接口 OK:")
print(df.head())
except Exception as e:
print(f"东方财富接口失败: {type(e).__name__}: {e}")
print("-" * 60)
# 尝试 2:新浪财经接口
try:
df = ak.stock_zh_a_daily(
symbol="sz000001",
start_date="20240101", end_date="20241231", adjust="",
)
print("新浪财经接口 OK:")
print(df.head())
except Exception as e:
print(f"新浪财经接口失败: {type(e).__name__}: {e}")
跑一下:
东方财富接口失败: ConnectionError: ('Connection aborted.', RemoteDisconnected(...))
------------------------------------------------------------
新浪财经接口 OK:
date open high low close volume amount outstanding_share turnover
0 2024-01-02 9.39 9.42 9.21 9.21 115836645.0 1.075742e+09 1.940555e+10 0.005969
1 2024-01-03 9.19 9.22 9.15 9.20 73361031.0 6.736736e+08 1.940555e+10 0.003780
2 2024-01-04 9.19 9.19 9.08 9.11 86419399.0 7.874701e+08 1.940555e+10 0.004453
3 2024-01-05 9.10 9.44 9.07 9.27 199162216.0 1.852660e+09 1.940555e+10 0.010263
4 2024-01-08 9.23 9.30 9.11 9.15 112115619.0 1.029007e+09 1.940555e+10 0.005778
至此,境外 IP 场景下的 AKShare 数据通路彻底跑通。
七、常用替代接口对照表
境外网络下,凡是 AKShare 里以 _em 结尾(东方财富)的接口都可能被风控。遇到不通就切换到对应的新浪/其他数据源实现:
| 场景 | 东方财富(可能失败) | 新浪财经(境外可用) |
|---|---|---|
| A 股日线 | stock_zh_a_hist | stock_zh_a_daily(symbol 带 sh/sz 前缀,如 sz000001) |
| A 股分钟线 | stock_zh_a_hist_min_em | stock_zh_a_minute |
| ETF 日线 | fund_etf_hist_em | fund_etf_hist_sina(symbol 如 sh510300) |
| 港股日线 | stock_hk_hist | stock_hk_daily |
字段名会略有不同(新浪返回的列名是英文 date/open/high/low/close/volume,东方财富是中文 日期/开盘/收盘...),后续处理时做个映射即可。
八、把整个流程固化成日常工作流
装完之后每次开新终端都要激活 venv、跑脚本,重复动作可以起个别名。在 ~/.zshrc 里加:
alias akenv="source ~/venvs/akshare/bin/activate"
以后新终端直接:
akenv
python3 fetch_data.py
不想在终端里看 DataFrame(观感差),可以装 JupyterLab 用交互式 notebook:
akenv
pip install jupyterlab
jupyter lab
浏览器会自动打开一个 notebook 环境,DataFrame 会直接渲染成漂亮的表格,画个 K 线图也就是几行 matplotlib 或 mplfinance 的事。
如何运行jupyter:新建 Notebook(最推荐)
Notebook 是 Jupyter 的核心用法,一格一格执行代码,适合数据探索和量化研究。
步骤:
- 左侧文件浏览器里
cd到你想放 notebook 的目录(比如新建一个~/quant-research/文件夹) - 点顶部的
+按钮打开 Launcher(启动器) - 在 “Notebook” 那一栏点
Python 3 (ipykernel),就新建了一个Untitled.ipynb文件 - 在第一个 cell 里写代码,按
Shift + Enter执行
目录结构
~/quant-research/
├── notebooks/ # Jupyter notebook 放这里
│ ├── akshare_test.ipynb
│ └── pingan_analysis.ipynb
├── scripts/ # .py 脚本放这里
│ └── pingan_2024.py
└── data/ # CSV/数据文件放这里
└── pingan_2024.csv
九、几个额外的排查经验
venv 之间完全隔离:~/venvs/akshare 和 ~/venvs/akshare313 之间的包互相看不见。装在哪个 venv 里,就只有激活那个 venv 才能 import。搞混了会出现”明明装过还是 ModuleNotFoundError”。
venv 里同时提供 pip 和 pip3:而在系统 Python 环境下(macOS 自带 + Homebrew 安装),Homebrew 版通常只提供 pip3 而没有 pip。所以在系统环境执行 pip install ... 会 command not found,改用 pip3 或先激活 venv。
pip 报 SSL 错误 UNEXPECTED_EOF_WHILE_READING:往往是代理节点当前不稳定导致 TLS 握手中断。可以退出代理工具重试、或者换个节点。这跟第四节的国内域名反爬是相反的问题——那次是”本该直连的走了代理”,这次是”本该走代理的代理不通”。
macOS 上 sed -i 要加 '':改 .zshrc 里的端口时要写 sed -i '' 's|旧|新|g' ~/.zshrc,跟 Linux 不一样,漏了会报错。
下一步计划
工具链层面基本齐了:Python 环境 + AKShare 数据源 + JupyterLab 交互探索。接下来这个系列会往两个方向延伸:
- 回测框架接入:把 AKShare 拉到的数据写进 vnpy 的 SQLite 数据库,跑一个基础的 ETF 双均线策略验证工具链
- 策略层探索:从简单的均线信号往上叠加,尝试用缠论笔段、MACD 背离等结构化信号做多因子
计划保持这个记录习惯,把每一步遇到的坑和实际排查思路留下来——比看别人的”完美教程”更接近真实工程情况。