3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
基于盈利收益率(Earnings Yield, EY)的选股策略是一种经典的价值投资策略。
盈利收益率是市盈率(P/E Ratio)的倒数,即:
$$ EY = \frac{E}{P} = \frac{1}{PE} $$
# -*- coding: utf-8 -*-
from jqdata import *
def initialize(context):
"""
初始化函数,设定基准、手续费、滑点等
"""
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 过滤掉order系列API产生的比error级别低的log
log.set_level('order', 'error')
# 设定股票类每笔交易时的手续费
set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
# 设定全局变量
g.stock_num = 20 # 持仓股票数量
g.index_security = '000300.XSHG' # 股票池:沪深300
# 设定按月运行,每月第一个交易日开盘后运行
run_monthly(rebalance, monthday=1, time='09:30')
def rebalance(context):
"""
调仓主函数
"""
# 1. 获取股票池(沪深300)
target_list = get_index_stocks(g.index_security, date=context.previous_date)
# 2. 过滤掉 停牌、ST、退市、次新股
target_list = filter_basic_stock(context, target_list)
# 3. 获取财务数据并进行排序(核心逻辑:低PE = 高盈利收益率)
# 查询 PE_TTM (市盈率-动态)
q = query(
valuation.code,
valuation.pe_ratio
).filter(
valuation.code.in_(target_list),
valuation.pe_ratio > 0 # 剔除亏损股(PE为负)
).order_by(
valuation.pe_ratio.asc() # 按PE从小到大排序,即盈利收益率从大到小
)
# 获取查询结果
df = get_fundamentals(q, date=context.previous_date)
# 取前 N 只股票
if len(df) > 0:
buy_list = list(df['code'][:g.stock_num])
else:
buy_list = []
# 4. 执行交易
trade(context, buy_list)
def filter_basic_stock(context, stock_list):
"""
基础过滤器:剔除停牌、ST、次新股
"""
current_data = get_current_data()
final_list = []
for stock in stock_list:
# 剔除停牌和已退市
if current_data[stock].paused:
continue
# 剔除ST
if current_data[stock].is_st:
continue
# 剔除上市不满60天的次新股
info = get_security_info(stock)
if not info or (context.current_dt.date() - info.start_date).days < 60:
continue
final_list.append(stock)
return final_list
def trade(context, buy_list):
"""
交易执行函数
"""
# 获取当前持仓
current_holdings = list(context.portfolio.positions.keys())
# 1. 卖出不在买入列表中的股票
for stock in current_holdings:
if stock not in buy_list:
order_target_value(stock, 0)
# log.info(f"卖出 {stock}")
# 如果没有需要买入的股票,直接返回
if len(buy_list) == 0:
return
# 2. 买入/调仓
# 计算每只股票的目标资金(等权重)
# 注意:这里使用 total_value 可能会导致满仓波动,实际操作中可预留少量现金
position_per_stk = context.portfolio.total_value / len(buy_list)
for stock in buy_list:
order_target_value(stock, position_per_stk)
# log.info(f"买入/调整 {stock} 到目标市值 {position_per_stk}")
选股逻辑 (rebalance 函数):
get_fundamentals 查询 valuation 表。valuation.pe_ratio 代表市盈率(TTM)。valuation.pe_ratio > 0:盈利收益率策略通常只针对盈利企业,因此剔除亏损股。order_by(valuation.pe_ratio.asc()):将市盈率从小到大排序。数学上,$\frac{1}{PE}$ 最大等同于 $PE$ 最小(在 $PE>0$ 的前提下)。过滤逻辑 (filter_basic_stock 函数):
get_current_data() 获取当天的停牌和ST状态,避免买入无法交易或风险过大的股票。get_security_info() 获取上市日期,剔除次新股,因为次新股的估值通常不稳定。交易逻辑 (trade 函数):
order_target_value 自动调整仓位。如果已持有该股且价格上涨,会自动卖出部分以保持权重;如果未持有,则买入。Q: 为什么不直接使用 1/PE 计算盈利收益率?
A: 在数据库查询层面,直接对 PE 进行升序排序(Ascending)的效果与计算 1/PE 后进行降序排序(Descending)的效果是完全一样的,且直接查询 PE 效率更高,代码更简洁。
Q: 这个策略适合什么市场环境?
A: 盈利收益率策略属于典型的价值策略。它通常在市场震荡期或熊市末期表现较好,因为这类股票具有较高的安全边际。在疯狂的牛市或成长股主导的行情中,该策略可能会跑输大盘。
Q: 如何改进这个策略?
A: