问题描述
解决方案
在 JoinQuant(聚宽)中,使用 query 对象配合 get_fundamentals 函数是进行复杂财务数据筛选的核心方法。
要实现同时筛选市值(位于 valuation 表)、市盈率(位于 valuation 表)和营业收入(位于 income 表),你需要进行多表联合查询。聚宽的 query 对象会自动处理表之间的连接。
以下是具体的实现步骤和代码示例:
核心步骤说明
- 导入库:需要
from jqdata import *。 - 构建 Query 对象:
- 使用
query()函数选择需要的字段(如代码、市值、PE、营收)。 - 使用
.filter()方法添加筛选条件。多个条件用逗号,分隔表示逻辑 与 (AND)。 - 使用
.order_by()进行排序(可选)。 - 使用
.limit()限制返回数量(可选,防止数据量过大)。
- 使用
- 执行查询:使用
get_fundamentals(q, date=...)获取数据。
代码示例
假设我们的筛选条件如下:
- 总市值:大于 100 亿元且小于 500 亿元(注意:聚宽市值单位为亿元)。
- 市盈率 (PE):0 到 30 倍之间(剔除亏损股)。
- 营业总收入:大于 50 亿元。
# -*- coding: utf-8 -*-
from jqdata import *
def initialize(context):
# 设定查询日期(在回测中通常使用 context.current_dt)
# 这里为了演示,我们指定一个具体日期,或者使用 context.previous_date
check_date = context.previous_date
# --- 构建查询语句 ---
q = query(
valuation.code, # 股票代码
valuation.market_cap, # 总市值(亿元)
valuation.pe_ratio, # 市盈率(PE, TTM)
income.total_operating_revenue # 营业总收入(元)
).filter(
# 1. 市值筛选:100亿 < 市值 < 500亿
valuation.market_cap > 100,
valuation.market_cap < 500,
# 2. 市盈率筛选:0 < PE < 30
valuation.pe_ratio > 0,
valuation.pe_ratio < 30,
# 3. 营业收入筛选:大于 50 亿 (注意 income 表单位是元)
income.total_operating_revenue > 5e9
).order_by(
# 按市值降序排列
valuation.market_cap.desc()
).limit(
# 最多取前50只
50
)
# --- 执行查询 ---
# get_fundamentals 会返回一个 pandas DataFrame
df = get_fundamentals(q, date=check_date)
# --- 打印结果 ---
if len(df) > 0:
log.info("筛选出的股票数量: %d" % len(df))
log.info(df.head()) # 打印前几行查看
# 获取股票代码列表
stock_list = list(df['code'])
log.info("选股列表: " + str(stock_list))
else:
log.info("未筛选出符合条件的股票")
def handle_data(context, data):
pass
关键点解析
-
数据表来源:
valuation(市值数据表):包含market_cap(总市值),pe_ratio(市盈率),pb_ratio(市净率) 等。income(利润表):包含total_operating_revenue(营业总收入),net_profit(净利润) 等。balance(资产负债表) 和cash_flow(现金流量表) 也可以按需加入。
-
单位问题:
valuation.market_cap的单位是 亿元。income和其他财务报表中的金额单位通常是 元。- 筛选时务必注意单位换算(如示例中
5e9代表 50 亿)。
-
多表连接:
- 当你在
query中同时引用valuation和income表的字段时,聚宽底层会自动根据股票代码和日期进行对齐(Join),你不需要手动写连接逻辑。
- 当你在
-
逻辑关系:
.filter(条件A, 条件B)默认是 AND 关系。- 如果需要 OR 关系,需要引入
or_函数:from sqlalchemy.sql.expression import or_ # ... .filter( or_( valuation.pe_ratio < 10, income.total_operating_revenue > 1e10 ) )
Q&A
Q: get_fundamentals 中的 date 参数和 statDate 参数有什么区别?
A:
date(推荐):查询指定日期(如 '2023-01-05')当时能看到的最新数据。它会自动处理财报发布的滞后性,避免未来函数。例如在 4 月 1 日查询,可能得到的是去年年报的数据,因为一季报还没发。statDate:查询指定财报周期的数据(如 '2022q4')。这通常用于特定财务分析,但在回测中如果使用不当(例如在 2023-01-01 获取了 2022q4 的数据,但实际上该财报可能在 2023-04 才发布),会导致未来函数,使回测结果虚高。
Q: 查询结果最多能返回多少条数据?
A: get_fundamentals 每次查询默认最多返回 5000 条数据。如果筛选结果可能超过这个限制,建议分批查询或增加更严格的筛选条件。
Q: 如何筛选“增长率”指标?
A: 增长率通常在 indicator 表中,例如 indicator.inc_revenue_year_on_year (营业收入同比增长率)。你可以像引入 income 表一样引入 indicator 表进行筛选。