问题描述
filter过滤时用逗号间隔,是同时满足吗?那就是和and一样呗?
为什么我通过逗号隔开的条件会选出不符合的股份?
解决方案
1. 逗号间隔代表“同时满足”(AND 逻辑)吗?
是的。 在 JoinQuant 的 get_fundamentals 查询中(底层使用的是 SQLAlchemy),filter() 方法里用逗号 , 隔开的多个条件,默认就是逻辑与(AND)的关系,即必须同时满足所有条件。
例如,以下代码表示选出“总市值大于1000亿” 且 “市盈率小于10”的股票:
q = query(
valuation.code
).filter(
valuation.market_cap > 1000,
valuation.pe_ratio < 10
)
2. 为什么会选出“不符合条件”的股票?
既然逗号代表同时满足,如果您发现选出的股票似乎不符合您设定的条件,通常是由以下几个常见原因导致的,建议您逐一排查:
原因一:查询日期(date)与您对比的数据日期不一致
get_fundamentals 函数在回测中,如果不指定 date 参数,默认获取的是 context.current_dt 的前一天的数据(因为当天交易时只能看到前一天的财报和市值数据)。
- 排查建议:检查您打印或对比的数据,是否是同一天的数据。市值、PE等估值数据每天都在变动。
原因二:单季度数据与 TTM 数据的混淆
JoinQuant 的财务表中,很多字段区分了“单季度/年度”和“TTM(滚动十二个月)”。
- 例如:
income.operating_revenue是单季度营业收入,而income.operating_revenue_ttm是过去12个月的营业收入。 - 排查建议:确认您
filter中使用的字段是否与您预期的一致。如果您用单季度利润去过滤,但去和炒股软件上的年度/TTM利润对比,就会发现“不符合”。
原因三:缺失值(NaN)导致逻辑异常
如果某只股票在某张财务表中没有数据(例如刚上市、或者某些金融股没有普通股的某些科目),数据库返回的可能是空值(NaN)。在某些复杂的比较逻辑中,缺失值可能会导致意外的过滤结果。
- 排查建议:将您
filter中用到的字段也一并query出来打印查看,看看那些“不符合”的股票,其对应的字段具体返回了什么数值。
原因四:使用了 or_ 函数但括号层级错误
如果您在查询中混合使用了 or_(逻辑或)和逗号(逻辑与),一定要注意括号的包裹范围。如果括号放错位置,会导致 AND 和 OR 的优先级混乱。
from sqlalchemy.sql.expression import or_
# 正确的混合使用示例:(条件A AND 条件B) OR 条件C
query(valuation.code).filter(
or_(
(valuation.market_cap > 1000) & (valuation.pe_ratio < 10), # 注意这里用 & 并且加括号
valuation.pb_ratio < 1
)
)
💡 终极排查方法
为了找出具体原因,建议您把用于过滤的字段直接查询出来并打印。例如:
q = query(
valuation.code,
valuation.market_cap,
valuation.pe_ratio
).filter(
valuation.market_cap > 1000,
valuation.pe_ratio < 10
)
df = get_fundamentals(q, date='2023-10-10')
print(df)
通过直接查看 df 打印出的 market_cap 和 pe_ratio 的具体数值,您就能立刻明白为什么这只股票会被选中了。