🚀 AI 一键生成 qmt 策略代码

QMT 价值投资策略:如何结合财务数据计算 PEG 指标进行选股?

qmt | 发布时间: 2025/12/8
以下内容由 EasyQuant 生成。

问题描述

我想写一个用PEG指标来选股的策略,应该如何获取计算所需的PE和利润增长率数据?

解决方案

在 QMT 平台中编写 PEG(市盈率相对盈利增长比率)选股策略,核心在于获取 PE(市盈率)G(净利润增长率) 数据。

根据 QMT API 文档,获取这两个指标最直接且高效的方法是使用 多因子数据接口 ContextInfo.get_factor_data。该接口可以直接返回经过清洗和计算的因子数据,避免了手动查询财务报表并计算的繁琐过程。

1. 数据获取方法

你需要使用以下两个核心步骤:

  1. 确定因子名称

    • PE (市盈率):在“股票因子_估值与市值”库中,字段名为 Valuation_and_Market_Cap.PE(通常指 TTM 或静态 PE,具体取决于数据源定义,QMT 默认 PE 通常较为通用)。
    • G (增长率):在“股票因子_成长能力”库中,最常用的是“归属母公司股东的净利润增长率”,字段名为 Growth.NPParentCompanyGrowRate
  2. 调用接口
    使用 ContextInfo.get_factor_data(fieldList, stockList, startDate, endDate) 获取数据。

2. PEG 策略实现代码

下面是一个完整的 PEG 选股策略示例。该策略逻辑如下:

  1. 选股范围:沪深 300 成分股。
  2. 计算 PEG:$PEG = \frac{PE}{Growth \times 100}$。
  3. 过滤条件
    • PE > 0(剔除亏损股)。
    • Growth > 0(剔除负增长)。
    • 0 < PEG < 1(寻找低估值高增长标的)。
  4. 交易逻辑:每月初调仓,买入 PEG 最小的前 10 只股票。
# -*- coding: gbk -*-
import pandas as pd
import numpy as np

def init(ContextInfo):
    # 设置账号(请替换为您的实际账号)
    ContextInfo.accid = '6000000000'
    ContextInfo.set_account(ContextInfo.accid)
    
    # 策略参数设置
    ContextInfo.target_num = 10  # 持仓最大数量
    ContextInfo.trade_period = '1m' # 运行周期,建议日线或月线
    
    # 设置股票池为沪深300
    ContextInfo.index_code = '000300.SH'
    
    print("PEG策略初始化完成")

def handlebar(ContextInfo):
    # 获取当前K线的时间
    index = ContextInfo.barpos
    timetag = ContextInfo.get_bar_timetag(index)
    current_date = timetag_to_datetime(timetag, '%Y%m%d')
    
    # 简单的月度调仓逻辑:仅在每月第一个交易日运行
    # 注意:这里使用简单的逻辑判断,实际回测建议配合定时器或更严格的日期判断
    if not ContextInfo.is_new_bar():
        return
        
    # 获取沪深300成分股
    stock_list = ContextInfo.get_sector(ContextInfo.index_code, timetag)
    if not stock_list:
        print("未获取到成分股")
        return

    # ----------------------------------------------------------------
    # 核心步骤:获取 PE 和 增长率 数据
    # ----------------------------------------------------------------
    # 字段定义:
    # Valuation_and_Market_Cap.PE : 市盈率
    # Growth.NPParentCompanyGrowRate : 归属母公司股东的净利润增长率
    fields = ['Valuation_and_Market_Cap.PE', 'Growth.NPParentCompanyGrowRate']
    
    # 获取因子数据 (返回 DataFrame)
    # 注意:get_factor_data 获取的是区间数据,这里我们取当日数据
    factor_data = ContextInfo.get_factor_data(fields, stock_list, current_date, current_date)
    
    if factor_data.empty:
        print(f"{current_date} 无因子数据")
        return

    # 数据处理:将数据转为 DataFrame 格式方便计算
    # get_factor_data 返回格式较为复杂,通常是 dict 或 multi-index DataFrame
    # 这里我们假设返回的是以股票代码为 Index,因子名为 Columns 的 DataFrame (当时间为单点时)
    # 如果返回的是 Dict (key为股票代码),需要转换
    
    df_factors = pd.DataFrame(index=stock_list)
    
    # 填充数据
    for stock in stock_list:
        if stock in factor_data:
            # 注意:根据API返回结构,这里可能需要适配
            # 如果 factor_data 是 dict: {stock: df}
            stock_df = factor_data[stock]
            if not stock_df.empty:
                df_factors.loc[stock, 'PE'] = stock_df['Valuation_and_Market_Cap.PE'].iloc[-1]
                df_factors.loc[stock, 'G'] = stock_df['Growth.NPParentCompanyGrowRate'].iloc[-1]
    
    # ----------------------------------------------------------------
    # 计算 PEG 指标
    # ----------------------------------------------------------------
    # 剔除无效数据 (NaN)
    df_factors.dropna(inplace=True)
    
    # 过滤逻辑:
    # 1. PE 必须为正 (亏损股没有计算 PEG 的意义)
    # 2. 增长率 G 必须为正
    df_factors = df_factors[(df_factors['PE'] > 0) & (df_factors['G'] > 0)]
    
    # 计算 PEG = PE / (G * 100) 
    # 注意:QMT中增长率通常是小数(如0.2代表20%),PEG公式中G通常取整数(20),所以要乘以100
    df_factors['PEG'] = df_factors['PE'] / (df_factors['G'] * 100)
    
    # 筛选 PEG 在 0 到 1 之间的低估值股票
    target_stocks_df = df_factors[(df_factors['PEG'] > 0) & (df_factors['PEG'] < 1)]
    
    # 按 PEG 从小到大排序,取前 N 只
    target_stocks_df = target_stocks_df.sort_values(by='PEG', ascending=True)
    buy_list = target_stocks_df.head(ContextInfo.target_num).index.tolist()
    
    print(f"日期: {current_date}, 选股数量: {len(buy_list)}")
    print(f"选股列表: {buy_list}")

    # ----------------------------------------------------------------
    # 交易执行
    # ----------------------------------------------------------------
    # 获取当前持仓
    positions = ContextInfo.get_trade_detail_data(ContextInfo.accid, 'stock', 'position')
    holding_list = [obj.m_strInstrumentID for obj in positions if obj.m_nVolume > 0]
    
    # 卖出不在买入列表中的股票
    for stock in holding_list:
        if stock not in buy_list:
            order_target_value(stock, 0, ContextInfo, ContextInfo.accid)
            print(f"卖出: {stock}")
            
    # 买入选中的股票
    if len(buy_list) > 0:
        # 简单的等权重分配资金
        # 获取账户总资产
        account_info = ContextInfo.get_trade_detail_data(ContextInfo.accid, 'stock', 'account')
        total_asset = account_info[0].m_dBalance if account_info else 1000000
        
        per_stock_value = total_asset / len(buy_list)
        
        for stock in buy_list:
            order_target_value(stock, per_stock_value, ContextInfo, ContextInfo.accid)
            print(f"买入: {stock}, 目标金额: {per_stock_value}")

3. 代码关键点解析

  1. ContextInfo.get_factor_data 的使用

    • 这是获取 PEG 所需数据的核心。
    • Valuation_and_Market_Cap.PE:获取市盈率。
    • Growth.NPParentCompanyGrowRate:获取净利润增长率。
    • 注意:在使用此接口前,请确保在 QMT 客户端菜单中点击 【数据管理】 -> 【补充数据】 -> 【多因子数据】,下载相应时间段的数据,否则回测或运行时会取不到值。
  2. PEG 计算公式

    • 代码中使用了 df_factors['PE'] / (df_factors['G'] * 100)
    • 这是因为 QMT 返回的增长率通常是小数形式(例如 0.5 代表 50%),而经典的 PEG 计算中分母通常直接使用百分比的数值(即 50),因此需要乘以 100。
  3. 数据清洗

    • PEG 指标对于亏损股(PE < 0)或负增长股(G < 0)没有参考意义,因此代码中通过 df_factors[(df_factors['PE'] > 0) & (df_factors['G'] > 0)] 进行了剔除。
  4. 交易执行

    • 使用了 order_target_value 函数进行调仓,这是一种目标价值下单方式,能够自动计算买卖数量将持仓调整到指定金额,非常适合这种定期轮动策略。

Q&A

Q: 为什么我运行代码时提示获取不到因子数据?
A: QMT 的多因子数据不是默认下载的。你需要手动去客户端的“数据管理”界面,选择“多因子数据”,并勾选你需要的时间段进行下载补充。

Q: 可以使用 TTM(滚动)市盈率吗?
A: 可以。虽然文档中 Valuation_and_Market_Cap.PE 通常即为 TTM 或包含 TTM 逻辑,但如果你想更精确地控制,可以使用 Valuation_and_Market_Cap.PE 配合财务数据自己计算,或者查看因子库中是否有明确标注 PE_TTM 的字段(不同券商版本的 QMT 因子库略有差异,建议在公式编辑器中查看具体的因子列表)。

Q: 如何获取预测的增长率而不是历史增长率?
A: 上述代码使用的是历史财务数据的增长率。如果需要预测数据,可以使用“股票因子_分析师预期”库中的字段,例如 Analyst_Estimation.FEARNG (未来预期盈利增长),但这需要你的 QMT 账号有相应的分析师预期数据权限。