🚀 AI 一键生成 joinquant 策略代码

JoinQuant API 进阶:如何使用 query 对象实现复杂财务数据筛选?

joinquant | 发布时间: 2025/12/16
以下内容由 EasyQuant 生成。

问题描述

如何用 query 对象实现复杂的财务数据筛选,比如同时筛选市值、市盈率和营业收入?

解决方案

在 JoinQuant(聚宽)中,使用 query 对象配合 get_fundamentals 函数是进行复杂财务数据筛选的核心方法。

要实现同时筛选市值(位于 valuation 表)、市盈率(位于 valuation 表)和营业收入(位于 income 表),你需要进行多表联合查询。聚宽的 query 对象会自动处理表之间的连接。

以下是具体的实现步骤和代码示例:

核心步骤说明

  1. 导入库:需要 from jqdata import *
  2. 构建 Query 对象
    • 使用 query() 函数选择需要的字段(如代码、市值、PE、营收)。
    • 使用 .filter() 方法添加筛选条件。多个条件用逗号 , 分隔表示逻辑 与 (AND)
    • 使用 .order_by() 进行排序(可选)。
    • 使用 .limit() 限制返回数量(可选,防止数据量过大)。
  3. 执行查询:使用 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

关键点解析

  1. 数据表来源

    • valuation (市值数据表):包含 market_cap (总市值), pe_ratio (市盈率), pb_ratio (市净率) 等。
    • income (利润表):包含 total_operating_revenue (营业总收入), net_profit (净利润) 等。
    • balance (资产负债表) 和 cash_flow (现金流量表) 也可以按需加入。
  2. 单位问题

    • valuation.market_cap 的单位是 亿元
    • income 和其他财务报表中的金额单位通常是
    • 筛选时务必注意单位换算(如示例中 5e9 代表 50 亿)。
  3. 多表连接

    • 当你在 query 中同时引用 valuationincome 表的字段时,聚宽底层会自动根据股票代码和日期进行对齐(Join),你不需要手动写连接逻辑。
  4. 逻辑关系

    • .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 表进行筛选。