3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在 JoinQuant (聚宽) 平台上,get_fundamentals_continuously 和 get_fundamentals 函数确实存在单次查询返回总条数不超过 5000 条的硬性限制(即:查询的股票数量 * count < 5000)。官方设置此限制主要是出于底层数据库性能和服务器资源保护的考虑,防止单次超大查询导致系统卡顿或崩溃。
虽然官方目前无法直接放开单次查询的硬性限制,但我们可以通过编写 Python 代码分批次循环获取数据并拼接的方式,轻松绕过这个限制,满足长周期时间序列分析的需求。
核心思路是:将一个长周期的时间段拆分成多个短周期(确保每次请求的数据量小于 5000),循环调用 API 获取数据,最后使用 pandas.concat 将结果合并。
以下代码展示了如何获取单只或多只股票超过 5000 条限制的 pe_ratio 数据:
import pandas as pd
import datetime
from jqdata import *
def get_long_term_fundamentals(query_object, end_date, total_count, step=100):
"""
分批获取长期财务数据,突破 5000 条限制
:param query_object: sqlalchemy.orm.query.Query 对象
:param end_date: 结束日期 (str 或 datetime)
:param total_count: 需要获取的总天数
:param step: 每次获取的天数 (需保证 股票数 * step < 5000)
:return: 拼接好的 pandas.DataFrame
"""
if isinstance(end_date, str):
end_date = datetime.datetime.strptime(end_date, '%Y-%m-%d').date()
elif isinstance(end_date, datetime.datetime):
end_date = end_date.date()
all_data = []
current_end_date = end_date
remaining_count = total_count
# 获取交易日历,用于精确计算时间推移
trade_days = get_all_trade_days()
trade_days = list(trade_days[trade_days <= current_end_date])
while remaining_count > 0:
# 计算本次需要获取的天数
current_step = min(step, remaining_count)
# 调用 API 获取数据 (注意:panel=False 返回 DataFrame 更易于处理)
df = get_fundamentals_continuously(query_object, end_date=current_end_date, count=current_step, panel=False)
if df is not None and not df.empty:
all_data.append(df)
remaining_count -= current_step
# 更新下一次查询的 end_date (往前推 current_step 个交易日)
if remaining_count > 0:
# 找到当前 end_date 在交易日历中的索引
try:
idx = trade_days.index(current_end_date)
# 往前推 current_step 天
if idx >= current_step:
current_end_date = trade_days[idx - current_step]
else:
break # 交易日历不足,退出
except ValueError:
break
if all_data:
# 将所有分批数据拼接起来,并按日期排序
final_df = pd.concat(all_data)
# 如果有重复数据可以去重
final_df = final_df.drop_duplicates()
return final_df
else:
return pd.DataFrame()
# --- 使用示例 ---
# 假设我们要查询 5 只股票过去 2000 个交易日(约 8 年)的 PE 数据
# 股票数(5) * count(2000) = 10000 > 5000,直接查会报错或数据不全
stocks = ['000001.XSHE', '600000.XSHG', '000002.XSHE', '600036.XSHG', '601398.XSHG']
q = query(valuation.code, valuation.day, valuation.pe_ratio).filter(valuation.code.in_(stocks))
# 每次查 500 天 (5只股票 * 500天 = 2500条 < 5000条)
long_term_df = get_long_term_fundamentals(q, end_date='2023-10-01', total_count=2000, step=500)
print(f"成功获取数据条数: {len(long_term_df)}")
print(long_term_df.head())
get_valuation 函数如果您仅仅是需要市值表(valuation)中的数据(例如 pe_ratio, pb_ratio, market_cap 等),JoinQuant 提供了一个专门的 API:get_valuation。
虽然 get_valuation 同样有每次最多返回 5000 条数据的限制,但它的调用方式更简单,同样可以通过上述的“分批按时间段循环”的方法来获取长周期数据。
step(每次查询的天数)乘以您的股票池数量,必须严格小于 5000。Panel 已被废弃,建议在调用 get_fundamentals_continuously 时显式设置 panel=False,直接获取 DataFrame,这样在后续使用 pd.concat 拼接时会更加方便。write_file 保存为 CSV 文件,后续直接 read_file 读取,这样可以大幅提升研究效率,减少 API 调用耗时。