问题描述
由于返回限制,只能调取4000家上市公司数据
此问题如何解决?
filter(finance.STK_EMPLOYEE_INFO.code==code):指定筛选条件,通过finance.STK_EMPLOYEE_INFO.code==code可以指定你想要查询的股票代码;除此之外,还可以对表中其他字段指定筛选条件,如finance.STK_EMPLOYEE_INFO.pub_date>=’2015-01-01’,表示公告日期大于2015年1月1日上市公司公布的员工信息;多个筛选条件用英文逗号分隔。
limit(n):限制返回的数据条数,n指定返回条数。
返回结果:
返回一个 dataframe, 每一行对应数据表中的一条数据, 列索引是你所查询的字段名称
注意:
为了防止返回数据量过大, 我们每次最多返回3000行
不能进行连表查询,即同时查询多张表的数据
解决方案
在 JoinQuant (聚宽) 平台中,为了防止单次查询占用过多内存和服务器资源,finance.run_query 和 get_fundamentals 等 API 确实对单次返回的数据行数做了限制(通常为 3000、4000 或 5000 行)。
要突破这个限制获取全量数据,核心思路是分批查询(循环获取)然后将结果拼接。以下为您提供三种最常用的解决方案:
方法一:使用 offset() 进行分页查询(最通用)
SQLAlchemy 的 query 对象支持 .offset(n) 方法,它可以跳过前 n 条数据。我们可以结合 limit() 和 offset() 写一个 while 循环,直到取不到数据为止。
import pandas as pd
from jqdata import *
def get_all_employee_info():
all_data = pd.DataFrame()
limit_size = 3000 # 每次最大获取条数
offset_size = 0 # 初始偏移量
while True:
# 构造查询,每次向后偏移 offset_size
q = query(finance.STK_EMPLOYEE_INFO).limit(limit_size).offset(offset_size)
df = finance.run_query(q)
# 如果返回的数据为空,说明已经取完,退出循环
if df.empty:
break
# 将本次获取的数据拼接到总表中
all_data = pd.concat([all_data, df], ignore_index=True)
# 增加偏移量,准备下一次查询
offset_size += limit_size
return all_data
# 调用函数获取全量数据
full_df = get_all_employee_info()
print("总共获取到数据条数:", len(full_df))
方法二:按股票代码分批查询(推荐用于横截面数据)
如果您只需要查询当前所有上市公司的某项数据,可以将全市场的股票代码列表切分成多个小块(例如每次查 500 只股票),然后循环查询。
import pandas as pd
from jqdata import *
def get_info_by_code_batches():
# 获取所有股票代码
all_stocks = list(get_all_securities(['stock']).index)
all_data = pd.DataFrame()
step = 500 # 每次查询500只股票,确保不会超过3000条限制
for i in range(0, len(all_stocks), step):
# 切片获取当前批次的股票代码
codes_batch = all_stocks[i : i+step]
# 使用 in_() 筛选当前批次的股票
q = query(finance.STK_EMPLOYEE_INFO).filter(
finance.STK_EMPLOYEE_INFO.code.in_(codes_batch)
)
df = finance.run_query(q)
all_data = pd.concat([all_data, df], ignore_index=True)
return all_data
方法三:按时间段分批查询(推荐用于历史时间序列数据)
如果您要获取的是多年的历史数据(例如每天的龙虎榜、多年的财务报表),按股票代码分批可能依然会超限,此时可以按时间(如按月、按季度)进行循环。
import pandas as pd
from jqdata import *
def get_info_by_date_batches():
all_data = pd.DataFrame()
# 生成按年或按月的日期范围
date_ranges = pd.date_range(start='2015-01-01', end='2023-01-01', freq='Y')
for i in range(len(date_ranges)-1):
start_dt = date_ranges[i].strftime('%Y-%m-%d')
end_dt = date_ranges[i+1].strftime('%Y-%m-%d')
q = query(finance.STK_EMPLOYEE_INFO).filter(
finance.STK_EMPLOYEE_INFO.pub_date >= start_dt,
finance.STK_EMPLOYEE_INFO.pub_date < end_dt
)
df = finance.run_query(q)
all_data = pd.concat([all_data, df], ignore_index=True)
return all_data
总结与建议
- 无特定筛选条件时:首选 方法一 (offset),代码最简单,逻辑最清晰。
- 需要特定股票池时:首选 方法二 (按代码分批),效率较高。
- 注意内存:如果获取的数据量极大(如几十万条),请注意研究环境的内存限制,建议将获取到的
DataFrame及时通过write_file保存为 CSV 文件,避免内存溢出。