问题描述
解决方案
在PTrade中,获取股票的市盈率数据(包括PE-TTM、静态市盈率和动态市盈率)需要使用 get_fundamentals 函数,并查询 valuation(估值数据)表。
核心字段说明
根据PTrade的API文档,valuation 表中对应的字段如下:
pe_ttm: 市盈率PE(TTM),即滚动市盈率(过去12个月)。pe_static: 静态市盈率(基于最近一期年报)。pe_dynamic: 动态市盈率(通常指基于当前季度数据年化后的市盈率)。
代码实现
以下是一个完整的策略示例,展示如何在 before_trading_start 函数中获取指定股票的这三种市盈率数据并打印到日志中。
def initialize(context):
# 初始化股票池,这里以恒生电子(600570.SS)为例
g.security = ['600570.SS']
set_universe(g.security)
def before_trading_start(context, data):
# 设定要查询的字段
# pe_ttm: 市盈率(TTM)
# pe_static: 静态市盈率
# pe_dynamic: 动态市盈率
fields = ['pe_ttm', 'pe_static', 'pe_dynamic', 'secu_name']
# 调用 get_fundamentals 获取估值数据
# 注意:在回测中,如果不传 date 参数,默认获取的是 context.blotter.current_dt (当日) 的数据。
# 为了避免“未来函数”(即在开盘前获取到了收盘后才更新的当日估值),建议在回测中传入前一个交易日的日期,
# 或者在 handle_data/after_trading_end 中获取当日数据。
# 此处演示直接获取,PTrade回测引擎通常会处理为获取截止到前一日的数据以防作弊,但具体依赖券商版本配置。
df = get_fundamentals(g.security, 'valuation', fields)
if df is not None and not df.empty:
log.info("获取到的市盈率数据如下:")
log.info(df)
# 演示如何提取具体数值 (假设只取第一只股票)
stock_code = g.security[0]
if stock_code in df.index:
pe_ttm = df.loc[stock_code, 'pe_ttm']
pe_static = df.loc[stock_code, 'pe_static']
log.info("股票 %s 的 PE-TTM: %s, 静态PE: %s" % (stock_code, pe_ttm, pe_static))
else:
log.info("未获取到数据")
def handle_data(context, data):
pass
注意事项
- 数据表来源:必须指定表名为
'valuation'。 - 查询模式:
valuation表只支持按天查询模式(即指定date或默认当前日期),不支持start_year/end_year的年份查询模式。 - 未来函数风险:在回测模式下,如果在
before_trading_start(盘前)不指定日期直接调用,系统可能会返回当日收盘后才结算出的市值和PE数据。为了严谨的回测,建议明确传入上一交易日的日期,或者知悉这一点仅作参考。 - 停牌处理:如果股票停牌,其市盈率数据通常会维持在停牌前的值。
Q&A
Q: pe_dynamic 和 pe_ttm 有什么区别?
A: pe_ttm (Trailing Twelve Months) 是滚动市盈率,使用过去4个季度的净利润总和计算,更能反映近期业绩。pe_dynamic 在PTrade中通常指动态市盈率,一般是根据最近一期财报(如一季报)的净利润乘以4(或相应倍数)来预估全年的净利润进行计算,波动性可能较大。
Q: 为什么获取到的数据是 NaN?
A: 可能原因包括:
- 该股票在查询日期停牌或未上市。
- 该股票业绩亏损(部分算法在亏损时返回负值,部分返回NaN,具体视数据源而定)。
- 查询日期是非交易日。
Q: 如何获取全市场股票的PE-TTM?
A: 可以先使用 get_Ashares() 获取全市场代码列表,然后将其作为 security 参数传入 get_fundamentals。但请注意,一次性查询几千只股票可能会导致超时或被限流,建议分批查询(例如每次500只)。