第4章:盘口数据获取实战
做量化交易,数据就是你的眼睛。没有数据,再好的策略也是瞎猜。
这一章,我们来点实在的。我会带你用 akshare 这个库,把ETF的实时盘口数据抓下来。然后解析买卖十档、算价差、算深度。嗯,都是做市商每天要看的东西。
4.1 为什么选 akshare?
说实话,国内能免费拿到实时行情的库不多。akshare 算是一个良心之作。它封装了新浪、腾讯等数据源,接口统一,用起来顺手。
我个人习惯是:开发阶段用 akshare 做数据验证,实盘阶段再切到券商API。为什么?因为免费接口有频率限制,你想想看,高频交易肯定不行。但做策略研究、回测、甚至低频做市,完全够用。
4.2 安装与导入
先装库,这个不用我多说了吧:
pip install akshare --upgrade
然后导入:
import akshare as ak
import pandas as pd
import time
嗯,这里要注意。akshare 更新比较频繁,建议每次运行前都升级一下。我曾经遇到过因为版本太旧,接口返回格式变了,导致解析报错。折腾了半天才发现是版本问题。
4.3 获取ETF实时行情
akshare 获取ETF实时行情,用的是 fund_etf_spot_em 这个接口。它会返回全市场ETF的实时数据。
# 获取所有ETF实时行情
df = ak.fund_etf_spot_em()
print(df.head())
返回的字段很多,我们重点关注这几个:
| 字段名 | 含义 | 说明 |
|---|---|---|
| 代码 | ETF代码 | 如 510050 |
| 名称 | ETF名称 | 如 上证50ETF |
| 最新价 | 当前成交价 | 单位:元 |
| 涨跌幅 | 当日涨跌百分比 | 正数为涨 |
| 成交量 | 当日累计成交量 | 单位:手 |
| 成交额 | 当日累计成交金额 | 单位:万元 |
如果你想只看某一只ETF,比如 510050:
# 筛选指定ETF
etf_code = '510050'
row = df[df['代码'] == etf_code]
print(row[['代码', '名称', '最新价', '涨跌幅']])
4.4 解析买卖十档数据
实时行情只能看到最新价,但做市商真正关心的是盘口深度。也就是买卖十档的挂单情况。
akshare 提供了 fund_etf_quote_em 接口,可以获取ETF的盘口数据:
# 获取指定ETF的盘口数据
quote_df = ak.fund_etf_quote_em(symbol="510050")
print(quote_df)
返回的数据结构是这样的:
| 字段 | 含义 |
|---|---|
| 买一价 ~ 买十价 | 买方各档位的挂单价格 |
| 买一量 ~ 买十量 | 买方各档位的挂单数量(单位:手) |
| 卖一价 ~ 卖十价 | 卖方各档位的挂单价格 |
| 卖一量 ~ 卖十量 | 卖方各档位的挂单数量(单位:手) |
我一般会这样解析:
# 提取买卖十档数据
buy_prices = [quote_df[f'买{i}价'].values[0] for i in range(1, 11)]
buy_volumes = [quote_df[f'买{i}量'].values[0] for i in range(1, 11)]
sell_prices = [quote_df[f'卖{i}价'].values[0] for i in range(1, 11)]
sell_volumes = [quote_df[f'卖{i}量'].values[0] for i in range(1, 11)]
print("买方挂单:")
for i in range(10):
print(f" 买{i+1}: 价格 {buy_prices[i]:.3f}, 数量 {buy_volumes[i]}手")
print("卖方挂单:")
for i in range(10):
print(f" 卖{i+1}: 价格 {sell_prices[i]:.3f}, 数量 {sell_volumes[i]}手")
4.5 计算盘口价差
盘口价差(Spread),就是卖一价和买一价的差值。这是做市商的核心利润来源。
# 计算盘口价差
bid1_price = quote_df['买一价'].values[0]
ask1_price = quote_df['卖一价'].values[0]
spread = ask1_price - bid1_price
spread_pct = spread / ((ask1_price + bid1_price) / 2) * 100
print(f"买一价: {bid1_price:.3f}")
print(f"卖一价: {ask1_price:.3f}")
print(f"绝对价差: {spread:.4f} 元")
print(f"相对价差: {spread_pct:.2f}%")
为什么这个指标重要?说白了,价差就是你的利润空间。你做市,就是在买一价买入,卖一价卖出,赚中间的差价。如果价差太小,扣除手续费后可能还亏钱。
我在项目中遇到过这样的情况:某只ETF平时价差在0.01元左右,但遇到市场剧烈波动时,价差能扩大到0.05元以上。这时候做市风险很大,我会选择缩小报价量,甚至暂停做市。
4.6 计算盘口深度
盘口深度,衡量的是市场在某个价格水平上的承接能力。简单说,就是你想买/卖大单时,市场能不能接住。
我一般会计算两个指标:
- 各档位累计深度:从买一累加到买十,看不同价格水平的总挂单量
- 加权平均深度:考虑价格因素,计算深度加权价格
# 计算累计深度
cum_buy_volume = 0
cum_sell_volume = 0
print("买方深度(累计):")
for i in range(10):
cum_buy_volume += buy_volumes[i]
print(f" 买{i+1}档累计: {cum_buy_volume}手")
print("\n卖方深度(累计):")
for i in range(10):
cum_sell_volume += sell_volumes[i]
print(f" 卖{i+1}档累计: {cum_sell_volume}手")
# 计算加权平均深度价格
weighted_bid_price = sum(buy_prices[i] * buy_volumes[i] for i in range(10)) / sum(buy_volumes)
weighted_ask_price = sum(sell_prices[i] * sell_volumes[i] for i in range(10)) / sum(sell_volumes)
print(f"\n买方加权平均价格: {weighted_bid_price:.3f}")
print(f"卖方加权平均价格: {weighted_ask_price:.3f}")
你想想看,如果买一到买五的深度很厚,但买六到买十几乎没单,说明市场只在当前价格附近有承接力。一旦价格跌破买五,可能就会快速下探。这就是所谓的「深度断层」。
4.7 完整代码示例
把上面的代码整合一下,写成一个完整的函数:
import akshare as ak
import pandas as pd
def get_etf_market_depth(etf_code):
"""
获取ETF盘口深度数据
:param etf_code: ETF代码,如 '510050'
:return: 盘口深度字典
"""
# 获取盘口数据
quote_df = ak.fund_etf_quote_em(symbol=etf_code)
# 解析买卖十档
buy_prices = [quote_df[f'买{i}价'].values[0] for i in range(1, 11)]
buy_volumes = [quote_df[f'买{i}量'].values[0] for i in range(1, 11)]
sell_prices = [quote_df[f'卖{i}价'].values[0] for i in range(1, 11)]
sell_volumes = [quote_df[f'卖{i}量'].values[0] for i in range(1, 11)]
# 计算价差
spread = sell_prices[0] - buy_prices[0]
mid_price = (sell_prices[0] + buy_prices[0]) / 2
spread_pct = spread / mid_price * 100
# 计算深度
total_bid_volume = sum(buy_volumes)
total_ask_volume = sum(sell_volumes)
# 返回结果
result = {
'code': etf_code,
'bid_prices': buy_prices,
'bid_volumes': buy_volumes,
'ask_prices': sell_prices,
'ask_volumes': sell_volumes,
'spread': spread,
'spread_pct': spread_pct,
'total_bid_depth': total_bid_volume,
'total_ask_depth': total_ask_volume
}
return result
# 使用示例
depth = get_etf_market_depth('510050')
print(f"ETF: {depth['code']}")
print(f"价差: {depth['spread']:.4f} ({depth['spread_pct']:.2f}%)")
print(f"买方总深度: {depth['total_bid_depth']}手")
print(f"卖方总深度: {depth['total_ask_depth']}手")
4.8 盘口分析框架图
下面这张图,是我做盘口分析时常用的框架。你可以把它当作一个检查清单:
这个框架,说白了就是四个步骤:拿数据 → 拆数据 → 算指标 → 做决策。每一步都有坑,我都在代码里加了注释,你跑一遍就明白了。
4.9 避坑指南
最后,分享几个我踩过的坑:
- 频率限制:akshare 的免费接口,建议每秒最多请求1次。我曾经写了个循环每秒请求10次,结果IP被临时封了半小时。
- 数据缺失:有些ETF在开盘初期或收盘前,盘口数据可能不完整。解析时一定要做异常处理。
- 价格精度:ETF的价格精度一般是3位小数,但有些是4位。计算价差时要注意精度问题,避免浮点数误差。
- 节假日:A股有节假日,非交易日调用接口会返回空数据。建议加个交易日判断。
好了,这一章的内容就到这里。代码你直接复制就能跑,跑通了再往下看。数据是交易的基础,把这一步做扎实了,后面的策略才能站得住脚。