🚀 AI 一键生成 joinquant 策略代码

JoinQuant 聚宽平台如何使用 SQLAlchemy 的 func 聚合字段(如 avg_pe)进行排序?

joinquant | 发布时间: 2026/5/21
以下内容由 EasyQuant 生成。

问题描述

sqlalchemy库 使用func 字段 排序

请问各位大佬比如下面这段代码,怎么在query中用新生成的'avg_pe'进行排序?

计算pe等指标时 ,需要排除掉为负的
q = query(valuation.day,
(func.count()/func.sum(1/valuation.pe_ratio)).label('avg_pe'), # 等权重pe
).filter(
valuation.pe_ratio>0, #排除亏损的

解决方案

在 JoinQuant (聚宽) 平台中,底层使用的是 SQLAlchemy 来构建数据库查询。当您使用 func 进行聚合计算并使用 .label() 命名后,想要对这个新生成的字段进行排序,通常有两种最直接有效的方法。

方法一:直接在 order_by 中重复聚合表达式(推荐)

这是最稳妥且兼容性最好的方法。直接将计算 avg_pe 的表达式放入 .order_by() 中,并调用 .desc()(降序)或 .asc()(升序)。

from jqdata import *
from sqlalchemy.sql import func

# 构建查询
q = query(
    valuation.day,
    (func.count() / func.sum(1 / valuation.pe_ratio)).label('avg_pe')
).filter(
    valuation.pe_ratio > 0
).group_by(
    valuation.day
).order_by(
    # 直接使用相同的表达式进行排序,这里以倒序(desc)为例
    (func.count() / func.sum(1 / valuation.pe_ratio)).desc()
).limit(10)

# 获取数据
df = get_fundamentals(q, date='2023-01-01')
print(df)

方法二:使用 sqlalchemy.textsqlalchemy.desc 引用 label 名称

如果您觉得重复写表达式太长,可以导入 SQLAlchemy 的相关模块,直接通过字符串引用您定义的 label 名称。

from jqdata import *
from sqlalchemy.sql import func
from sqlalchemy import desc, text

# 构建查询
q = query(
    valuation.day,
    (func.count() / func.sum(1 / valuation.pe_ratio)).label('avg_pe')
).filter(
    valuation.pe_ratio > 0
).group_by(
    valuation.day
).order_by(
    # 使用 text 引用 label 名称进行排序
    text('avg_pe DESC')
    # 或者使用 desc(text('avg_pe'))
).limit(10)

# 获取数据
df = get_fundamentals(q, date='2023-01-01')
print(df)

注意事项:

  1. group_by 是必须的:当您使用了聚合函数(如 func.count(), func.sum())并且查询中还包含非聚合字段(如 valuation.day)时,必须加上 .group_by(valuation.day),否则 SQL 语法会报错或返回非预期结果。
  2. 除零错误:虽然您使用了 valuation.pe_ratio > 0 过滤了负数和零,但在实际应用中,如果某一天没有任何符合条件的股票,func.sum 可能返回 NULL,导致除法报错。在 JoinQuant 的 get_fundamentals 中通常会自动处理,但需留意数据清洗。
  3. 性能考虑:在 get_fundamentals 中进行复杂的聚合计算可能会比较慢,如果查询超时,建议先取出基础数据(如 pe_ratio),然后使用 Pandas 在内存中进行 groupby 和聚合计算。