🚀 AI 一键生成 qmt 策略代码

如何用 QMT 搭建一个基于市盈率(PE)和净资产收益率(ROE)的价值选股策略?

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

问题描述

请帮我写一个价值投资策略,定期筛选并买入低估值的股票。

解决方案

这是一个基于 QMT (Quant Trader) 平台的价值投资策略示例。

策略逻辑

  1. 选股范围:沪深300指数成分股(代表大盘蓝筹,流动性好)。
  2. 选股因子:市盈率(PE)和 市净率(PB)。
  3. 筛选规则
    • 剔除市盈率为负(亏损)的股票。
    • 按照 市盈率 (PE) 从低到高排序。
    • 选取排名前 10 的股票。
  4. 调仓周期月度调仓(每个月第一个交易日进行检查和调整)。
  5. 交易方式:等权重买入。

策略代码

# -*- coding: gbk -*-
import pandas as pd
import time

def init(ContextInfo):
    """
    初始化函数,策略启动时执行一次
    """
    # 1. 设置策略参数
    ContextInfo.stock_num = 10       # 持仓股票数量
    ContextInfo.index_code = '000300.SH' # 股票池:沪深300
    ContextInfo.last_month = -1      # 用于记录上一次调仓的月份
    
    # 2. 设置账号(回测模式下通常默认为 'test',实盘请修改为真实资金账号)
    ContextInfo.accid = 'test' 
    ContextInfo.set_account(ContextInfo.accid)
    
    print("策略初始化完成,开始运行价值投资策略...")

def handlebar(ContextInfo):
    """
    行情事件函数,每根K线执行一次
    """
    # 获取当前K线的时间
    bar_index = ContextInfo.barpos
    timetag = ContextInfo.get_bar_timetag(bar_index)
    current_date_str = timetag_to_datetime(timetag, '%Y%m%d')
    current_month = int(current_date_str[4:6]) # 提取月份
    
    # --- 1. 调仓时间控制 (月度调仓) ---
    # 如果当前月份与上一次调仓月份相同,则跳过,不进行操作
    if current_month == ContextInfo.last_month:
        return

    # 更新调仓月份标记
    ContextInfo.last_month = current_month
    print(f"=== 检测到新月份 {current_date_str},开始执行选股调仓 ===")

    # --- 2. 获取股票池 ---
    # 获取沪深300成分股
    stock_list = ContextInfo.get_sector(ContextInfo.index_code)
    if not stock_list:
        print("获取成分股失败或为空")
        return

    # --- 3. 获取因子数据 (PE 和 PB) ---
    # 注意:根据QMT文档,因子字段需使用英文名
    # Valuation_and_Market_Cap.PE : 市盈率
    # Valuation_and_Market_Cap.PB : 市净率
    factor_fields = ['Valuation_and_Market_Cap.PE', 'Valuation_and_Market_Cap.PB']
    
    # 获取当天的因子数据
    # 返回格式:pandas.DataFrame index=代码 ,columns=字段
    factor_data = ContextInfo.get_factor_data(
        factor_fields, 
        stock_list, 
        current_date_str, 
        current_date_str
    )
    
    if factor_data.empty:
        print("未获取到因子数据")
        return

    # --- 4. 数据清洗与选股逻辑 ---
    df = factor_data.copy()
    
    # 4.1 去除空值
    df.dropna(inplace=True)
    
    # 4.2 剔除亏损股 (PE <= 0)
    df = df[df['Valuation_and_Market_Cap.PE'] > 0]
    
    # 4.3 按照 PE 从低到高排序 (价值投资核心)
    df.sort_values(by='Valuation_and_Market_Cap.PE', ascending=True, inplace=True)
    
    # 4.4 选取排名前 N 的股票
    target_stocks = df.head(ContextInfo.stock_num).index.tolist()
    print(f"本期选中股票 ({len(target_stocks)}只): {target_stocks}")

    # --- 5. 执行交易 (等权重) ---
    if len(target_stocks) > 0:
        target_weight = 1.0 / len(target_stocks) # 单只股票目标仓位权重
        
        # 5.1 卖出不在目标列表中的持仓
        # 获取当前持仓
        positions = get_trade_detail_data(ContextInfo.accid, 'stock', 'position')
        current_holdings = [obj.m_strInstrumentID for obj in positions]
        
        for stock in current_holdings:
            if stock not in target_stocks:
                # 目标权重设为0,即清仓
                order_target_percent(stock, 0, ContextInfo, ContextInfo.accid)
                print(f"卖出非目标股: {stock}")
        
        # 5.2 买入/调整目标股票
        for stock in target_stocks:
            # 目标权重下单,QMT会自动计算需要买卖的数量
            order_target_percent(stock, target_weight, ContextInfo, ContextInfo.accid)
            print(f"调整 {stock} 仓位至 {target_weight:.2%}")

代码关键点解析

  1. # -*- coding: gbk -*-:

    • QMT 的 Python 编辑器默认编码通常是 GBK,加上这行可以防止中文注释乱码。
  2. ContextInfo.get_factor_data:

    • 这是 QMT 获取基本面数据的核心接口。我们使用了 Valuation_and_Market_Cap.PE(市盈率)作为核心筛选指标。
    • 注意:在使用此接口前,请务必在 QMT 客户端菜单中点击 【数据管理】 -> 【补充数据】 -> 【多因子数据】,下载对应时间段的数据,否则回测时会取不到数据。
  3. order_target_percent:

    • 这是一个非常方便的交易函数。你只需要告诉它你希望某只股票占总资产的百分比(例如 10%),它会自动计算当前持仓与目标持仓的差额,并自动发出买单或卖单。
  4. 调仓逻辑:

    • 代码中使用 current_monthlast_month 对比。一旦月份发生变化(例如从 1月变到 2月),就会触发一次选股和交易。

如何在 QMT 中运行

  1. 打开 QMT 客户端,进入 【模型研究/策略研究】
  2. 新建一个 Python 策略
  3. 将上述代码复制粘贴到编辑器中。
  4. 补充数据:确保你已经下载了“沪深300”成分股的历史行情数据和多因子数据。
  5. 设置回测参数
    • 周期:选择 日线 (1d)
    • 时间:选择一段历史时间(例如最近2年)。
    • 基准:沪深300。
  6. 点击 【回测】 查看策略表现。

常见问题 Q&A

Q: 为什么回测没有交易记录?
A: 最大的可能是没有下载多因子数据。请去数据管理界面下载。另外,请检查回测时间段内是否包含交易日。

Q: 如何修改为按 PB(市净率)选股?
A: 将代码中排序的那一行:
df.sort_values(by='Valuation_and_Market_Cap.PE', ...)
修改为:
df.sort_values(by='Valuation_and_Market_Cap.PB', ...) 即可。

Q: 实盘可以直接用吗?
A: 实盘需要将 init 函数中的 ContextInfo.accid = 'test' 修改为您真实的资金账号,并将策略运行模式切换为“实盘”或“模拟”。建议先在模拟盘充分测试。