第1章:流动性数据获取——从零开始抓取LOF实时行情
大家好,我是你们的LOF套利实战导师。今天咱们正式开讲《LOF流动性管理从零开始》的第一章。
做LOF套利,说白了就是跟流动性打交道。没有数据,一切都是空谈。我见过太多新手,上来就搞策略、写模型,结果连行情数据都拿不到——嗯,那真是白忙活。
这一章,我带大家搞定三件事:实时行情、盘口深度、历史成交。这三样东西,是LOF套利的“三驾马车”。
核心观点:流动性数据是LOF套利的“眼睛”。没有数据,你就是在黑夜里开车。
1.1 数据源选择:tushare vs akshare
我个人习惯用两个库:tushare 和 akshare。它们各有千秋,我分别说说。
| 对比项 | tushare | akshare |
|---|---|---|
| 数据覆盖 | 全面,含LOF实时行情 | 更广,含盘口深度 |
| 使用门槛 | 需要注册获取token | 免费,无需注册 |
| 稳定性 | 高,有付费版 | 中等,依赖源网站 |
| 盘口深度 | 不支持 | 支持(东方财富源) |
| 历史数据 | 支持,按天获取 | 支持,可获取分钟级 |
我的建议是:两个都装。tushare做主力,akshare做补充。尤其是盘口深度数据,tushare目前不支持,得靠akshare。
小技巧:我在项目中遇到过tushare token过期的情况。建议把token写在配置文件里,定期检查。别问我怎么知道的——有一次凌晨跑策略,突然报错,那叫一个酸爽。
1.2 实时行情获取:tushare实战
先上代码。这是我最常用的实时行情获取函数:
import tushare as ts
import pandas as pd
from datetime import datetime
# 初始化tushare
ts.set_token('你的token')
pro = ts.pro_api()
def get_lof_realtime(ticker):
"""
获取LOF实时行情
:param ticker: LOF代码,如 '501018'
:return: DataFrame
"""
# 获取实时行情
df = pro.realtime_tick(ts_code=f'{ticker}.SZ')
if df.empty:
print(f'警告:{ticker} 无数据,可能未上市或停牌')
return None
# 提取关键字段
result = {
'代码': ticker,
'最新价': df['price'].iloc[0],
'涨跌幅': df['pct_chg'].iloc[0],
'成交量': df['vol'].iloc[0],
'成交额': df['amount'].iloc[0],
'时间': datetime.now().strftime('%H:%M:%S')
}
return pd.DataFrame([result])
# 测试
if __name__ == '__main__':
df = get_lof_realtime('501018')
print(df)
这里有个坑,我提醒一下:LOF代码后面要加交易所后缀。深交所的LOF用.SZ,上交所的用.SH。我曾经因为这个后缀写错过,结果查了半天数据都是空的——后来才发现是代码写成了.SS。
注意:tushare的realtime_tick接口在交易时段外返回空数据。如果你在非交易时间测试,别慌,不是代码问题。
1.3 盘口深度数据:akshare上场
盘口深度,说白了就是买卖五档的挂单情况。这对LOF套利至关重要——你想想看,如果买一和卖一之间价差很大,说明流动性差,套利空间可能被吃掉。
akshare从东方财富源获取盘口数据,代码很简单:
import akshare as ak
def get_lof_depth(ticker):
"""
获取LOF盘口深度数据
:param ticker: LOF代码,如 '501018'
:return: dict
"""
# 获取盘口数据
df = ak.stock_individual_info_em(symbol=ticker)
# 获取买卖五档
bid_ask = ak.stock_bid_ask_em(symbol=ticker)
# 整理输出
depth = {
'买五': bid_ask['买五价'].iloc[0] if '买五价' in bid_ask.columns else None,
'买四': bid_ask['买四价'].iloc[0] if '买四价' in bid_ask.columns else None,
'买三': bid_ask['买三价'].iloc[0] if '买三价' in bid_ask.columns else None,
'买二': bid_ask['买二价'].iloc[0] if '买二价' in bid_ask.columns else None,
'买一': bid_ask['买一价'].iloc[0] if '买一价' in bid_ask.columns else None,
'卖一': bid_ask['卖一价'].iloc[0] if '卖一价' in bid_ask.columns else None,
'卖二': bid_ask['卖二价'].iloc[0] if '卖二价' in bid_ask.columns else None,
'卖三': bid_ask['卖三价'].iloc[0] if '卖三价' in bid_ask.columns else None,
'卖四': bid_ask['卖四价'].iloc[0] if '卖四价' in bid_ask.columns else None,
'卖五': bid_ask['卖五价'].iloc[0] if '卖五价' in bid_ask.columns else None,
}
# 计算价差
if depth['买一'] and depth['卖一']:
depth['价差'] = depth['卖一'] - depth['买一']
depth['价差率'] = depth['价差'] / depth['买一'] * 100
else:
depth['价差'] = None
depth['价差率'] = None
return depth
# 测试
depth = get_lof_depth('501018')
print(f"买一: {depth['买一']}, 卖一: {depth['卖一']}")
print(f"价差: {depth['价差']:.4f}, 价差率: {depth['价差率']:.2f}%")
为什么价差这么重要?我举个例子。有一次我盯着一只LOF,买一1.200,卖一1.205,价差0.005元。看起来不大,但换算成年化收益率,如果每天做一次套利,年化能到15%以上。后来流动性变差,价差扩大到0.02元,套利空间直接被吃掉了。
核心指标:价差率 < 0.5% 算流动性好,0.5%-1% 算一般,> 1% 算差。这是我个人经验,你可以根据自己策略调整。
1.4 历史成交数据:构建回测基础
历史数据是回测的基础。没有历史数据,你怎么知道策略在过去表现如何?
我用tushare获取日线历史数据:
def get_lof_history(ticker, start_date, end_date):
"""
获取LOF历史日线数据
:param ticker: LOF代码
:param start_date: 起始日期 '20240101'
:param end_date: 结束日期 '20241231'
:return: DataFrame
"""
df = pro.fund_daily(
ts_code=f'{ticker}.SZ',
start_date=start_date,
end_date=end_date,
fields='trade_date,open,high,low,close,vol,amount'
)
# 排序
df = df.sort_values('trade_date')
df = df.reset_index(drop=True)
# 计算一些常用指标
df['涨跌幅'] = df['close'].pct_change() * 100
df['换手率'] = df['vol'] / df['vol'].rolling(20).mean()
return df
# 获取2024年全年数据
hist = get_lof_history('501018', '20240101', '20241231')
print(hist.tail())
这里有个细节:换手率是我自己加的。换手率突然放大,往往意味着有资金在搞事情。我在做套利时,会特别关注换手率超过均值2倍以上的日子——那通常是套利机会出现的时候。
1.5 知识体系总览
为了让你更直观地理解本章的知识结构,我画了一张图:
1.6 实战中的避坑指南
最后,我分享几个实战中踩过的坑:
- 数据延迟问题:tushare的实时数据有1-3秒延迟。做高频套利时,这个延迟可能致命。我一般会用akshare的websocket接口做补充。
- 停牌处理:LOF也会停牌。停牌期间所有数据接口返回空。我写了个自动检测函数,如果连续5分钟无数据,就发邮件报警。
- 复权问题:历史数据默认是未复权的。做回测时一定要用复权数据,否则分红除权后你的策略曲线会失真。
- 数据存储:别每次都从接口拉数据。我习惯每天收盘后把数据存到本地SQLite,第二天直接用本地数据,快很多。
我的习惯:每天早上开盘前,我会跑一遍所有数据获取脚本,检查数据是否正常。如果发现某只LOF数据异常,立刻人工排查。这个习惯帮我避免了好几次因为数据问题导致的策略误判。
好了,第一章的内容就到这里。数据获取是基础中的基础,但也是最容易出问题的地方。把这三样东西搞定了,后面的流动性分析、套利策略才有根基。
记住:数据质量决定策略质量。别嫌麻烦,把数据源、存储、监控都做好,后面你会感谢自己的。