3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在PTrade中计算沪深300指数的加权市盈率(Weighted P/E Ratio),核心思路是**“总市值除以总净利润”**。
相比于简单算术平均(即所有股票PE相加除以数量),加权市盈率更能反映指数整体的估值水平,因为它考虑了权重股(大市值公司)的影响。
$$ \text{指数加权市盈率} = \frac{\sum(\text{成分股总市值})}{\sum(\text{成分股净利润})} $$
由于PTrade的get_fundamentals接口直接提供了总市值(total_value)和市盈率TTM(pe_ttm),我们可以通过以下公式反推净利润,从而避免去查利润表:
$$ \text{个股净利润} = \frac{\text{个股总市值}}{\text{个股市盈率TTM}} $$
before_trading_start中使用get_index_stocks获取沪深300成分股列表。get_fundamentals查询成分股的total_value(总市值)和pe_ttm(滚动市盈率)。total_value得到总市值。total_value / pe_ttm计算每只股票的净利润,并累加得到总净利润(亏损企业的负利润也应包含在内)。以下是完整的策略代码实现:
def initialize(context):
# 设置基准为沪深300
set_benchmark('000300.SS')
# 设置回测频率为日线
set_universe(['000300.SS'])
# 开启日志打印
log.info("策略初始化完成,准备计算沪深300加权市盈率")
def before_trading_start(context, data):
# 1. 获取沪深300指数的成分股列表
# 注意:get_index_stocks 建议在盘前处理函数中调用
index_code = '000300.SS'
stocks = get_index_stocks(index_code)
if not stocks:
log.error("未获取到成分股数据")
return
# 2. 获取估值数据:总市值(total_value) 和 市盈率TTM(pe_ttm)
# total_value 单位是元
df = get_fundamentals(stocks, 'valuation', ['total_value', 'pe_ttm'])
if df is None or len(df) == 0:
log.warning("未获取到财务数据")
return
# 3. 数据清洗与计算
# 剔除市盈率为0或空的数据(防止除以0错误),通常PE不会为0,但需防范数据异常
# 注意:亏损股的PE为负数,计算总利润时应保留负值,这样才能真实反映指数估值
df = df.dropna()
# 计算个股净利润 (Net Profit = Market Cap / PE)
# 这里使用向量化运算提高效率
df['net_profit'] = df['total_value'] / df['pe_ttm']
# 4. 计算指数整体指标
total_market_cap = df['total_value'].sum() # 总市值
total_net_profit = df['net_profit'].sum() # 总净利润
# 5. 计算加权市盈率
if total_net_profit != 0:
weighted_pe = total_market_cap / total_net_profit
# 打印结果
log.info("日期: %s" % context.blotter.current_dt.strftime("%Y-%m-%d"))
log.info("沪深300成分股数量: %d" % len(df))
log.info("沪深300总市值: %.2f 亿" % (total_market_cap / 100000000))
log.info("沪深300加权市盈率(TTM): %.4f" % weighted_pe)
# 可以将结果存入全局变量g中,供handle_data使用
g.hs300_pe = weighted_pe
else:
log.error("总净利润为0,无法计算市盈率")
def handle_data(context, data):
# 在这里可以根据 g.hs300_pe 进行交易逻辑判断
# 例如:如果PE低于历史分位数则买入ETF等
pass
数据获取接口:
get_index_stocks('000300.SS'):获取最新的成分股,这比固定股票列表更准确,因为指数成分股会定期调整。get_fundamentals(..., 'valuation', ...):这是获取每日估值数据的核心接口。净利润推导:
df['total_value'] / df['pe_ttm'] 来反推净利润。这是量化中常用的技巧,因为直接查利润表(income_statement)通常是季度数据,存在滞后性,而pe_ttm是基于最新股价和最近4个季度财报计算的,实时性更强。负值处理:
Python版本兼容性:
Q1: 为什么要计算加权市盈率而不是算术平均市盈率?
A: 算术平均(等权)容易受小市值股票极端值的影响。例如,某小市值股票利润极低导致PE高达几千倍,会拉高平均值。加权市盈率通过市值加权,更能反映市场中资金容纳量最大的那些核心资产的估值水平,是判断指数贵贱的主流指标。
Q2: 代码中的 pe_ttm 可以换成静态市盈率 pe_static 吗?
A: 可以。如果将代码中的 'pe_ttm' 替换为 'pe_static',计算出的就是静态加权市盈率。静态PE基于上年度年报数据,TTM基于最近12个月数据。通常在财报发布季(如4月、10月),两者差异可能较大,TTM通常更具时效性。
Q3: 如何利用这个数据进行择时交易?
A: 您可以获取过去5年或10年的加权PE数据,计算当前PE所处的历史百分位。
Q4: 为什么计算结果和某些行情软件(如Wind、同花顺)显示的数值有细微差异?
A: 差异通常来源于: