Skip to content
Go back

量化交易探索-工具篇(一):macOS 上从零搭建 AKShare 数据环境

Edit page

作为量化交易探索系列的第一篇,先解决”数据从哪来”的问题。选型上直接锁定 AKShare——纯 Python 库、覆盖 A 股/港股/美股/期货/期权/基金/宏观数据、一行代码返回 pandas DataFrame,接口密度和文档完备度在开源界里是最高的一档。它自己不产生数据,而是把东方财富、新浪财经、各大交易所官网的公开数据抓取清洗后统一封装,学术研究或者个人策略研发场景都够用了。

这篇文章不是”教程搬运”,而是我在 MacBook M5 上完整跑一遍从环境搭建到拿到数据的实录,包括中间遇到的每一个坑和排查思路。目标读者:想在自己 Mac 上跑起来数据接口的开发者。

Table of contents

Open Table of contents

环境规划

先明确要装什么、装到哪:

这里有个反直觉的点值得先说清楚:要用 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 股日线还有:

新浪那边的接口反爬没这么严格,境外可用。写一个双接口对照的诊断脚本:

# 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_histstock_zh_a_daily(symbol 带 sh/sz 前缀,如 sz000001
A 股分钟线stock_zh_a_hist_min_emstock_zh_a_minute
ETF 日线fund_etf_hist_emfund_etf_hist_sina(symbol 如 sh510300
港股日线stock_hk_histstock_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 的核心用法,一格一格执行代码,适合数据探索和量化研究。

步骤:

  1. 左侧文件浏览器里 cd 到你想放 notebook 的目录(比如新建一个 ~/quant-research/ 文件夹)
  2. 点顶部的 + 按钮打开 Launcher(启动器)
  3. 在 “Notebook” 那一栏点 Python 3 (ipykernel),就新建了一个 Untitled.ipynb 文件
  4. 在第一个 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 里同时提供 pippip3:而在系统 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 交互探索。接下来这个系列会往两个方向延伸:

  1. 回测框架接入:把 AKShare 拉到的数据写进 vnpy 的 SQLite 数据库,跑一个基础的 ETF 双均线策略验证工具链
  2. 策略层探索:从简单的均线信号往上叠加,尝试用缠论笔段、MACD 背离等结构化信号做多因子

计划保持这个记录习惯,把每一步遇到的坑和实际排查思路留下来——比看别人的”完美教程”更接近真实工程情况。

参考资料


Edit page
Share this post on:

Previous Post
AstroPaper 博客本地构建与 Vercel 部署实录
Next Post
Claude Code 源码架构深度解析