问题描述
query(valuation).filter(valuation.code.in_(stocks))
这个函数要怎么理解啊?
他的输出是什么,为什么需要这样一个函数。感觉很奇怪。
解决方案
JoinQuant 中 query().filter() 函数详解
在 JoinQuant(聚宽)量化平台中,query().filter() 并不是一个孤立的函数,它是用来构建数据库查询语句的核心工具,通常与 get_fundamentals() 函数配合使用,用于获取上市公司的财务数据和市值数据。
它的底层实际上是基于 Python 著名的数据库 ORM 框架 SQLAlchemy 构建的。
1. 逐句解析 query(valuation).filter(valuation.code.in_(stocks))
这句话的作用是构建一个查询对象(Query Object),告诉系统你想从数据库里查什么数据。
-
query(valuation):query()是查询的起点,相当于 SQL 语句中的SELECT。valuation代表市值数据表。这句话的意思是:“我要查询市值表(valuation)里的所有字段(如总市值、流通市值、市盈率等)”。- 如果你只需要特定的字段,可以写成
query(valuation.code, valuation.market_cap)。
-
.filter(...):- 相当于 SQL 语句中的
WHERE,用于设置过滤条件。
- 相当于 SQL 语句中的
-
valuation.code.in_(stocks):- 这是具体的过滤条件。
valuation.code指的是市值表中的股票代码列。 .in_(stocks)表示股票代码必须存在于stocks这个列表(list)中。- 连起来的意思是:“只查询股票代码在
stocks列表中的那些股票的数据”。
- 这是具体的过滤条件。
2. 它的输出是什么?
单独运行 query(valuation).filter(valuation.code.in_(stocks)),它的输出只是一个 Query 对象(相当于一句准备好的 SQL 语句),并没有真正去数据库里拉取数据。
要获取真实的数据,必须把这个 Query 对象传给 get_fundamentals() 函数执行:
# 1. 准备股票池
stocks = ['000001.XSHE', '600000.XSHG']
# 2. 构建查询对象
q = query(valuation).filter(valuation.code.in_(stocks))
# 3. 执行查询,获取数据(指定日期)
df = get_fundamentals(q, date='2023-10-15')
# 4. 打印结果
print(df)
最终的输出(df)是一个 pandas.DataFrame 表格,每一行代表一只股票,每一列代表市值表中的一个字段(如 code, market_cap, pe_ratio 等)。
3. 为什么需要这样一个函数?感觉很奇怪?
对于刚接触量化或没有数据库基础的同学来说,这种写法可能略显繁琐,但它有非常重要的原因:
A. 避免内存爆炸(按需查询)
A股有 5000 多只股票,财务数据表包含成百上千个字段,历史数据极其庞大。如果平台提供一个简单的函数 get_all_finance_data() 一次性把所有数据拉下来,你的内存会瞬间撑爆,程序会直接崩溃。通过 query().filter(),你可以精准地只拉取你需要的几只股票、几个特定字段,极大节省内存和查询时间。
B. 极高的灵活性(支持复杂条件筛选)
你可以用它进行非常复杂的选股逻辑。例如,你想选出:“总市值大于 100 亿,且市盈率小于 20,且营业收入大于 200 亿的股票”,只需这样写:
q = query(
valuation.code,
valuation.market_cap,
valuation.pe_ratio
).filter(
valuation.market_cap > 100, # 市值大于100亿
valuation.pe_ratio < 20, # 市盈率小于20
income.total_operating_revenue > 2e10 # 营收大于200亿
).order_by(
valuation.market_cap.desc() # 按市值降序排列
).limit(50) # 最多只取50只
df = get_fundamentals(q, date='2023-10-15')
这种链式调用的写法(ORM)在数据分析和后端开发中非常标准且强大。习惯之后,你会发现它比普通的函数传参要灵活得多。