🚀 AI 一键生成 qmt 策略代码
立即体验

QMT 基本面选股:基于杜邦分析法 (DuPont Analysis) 的因子模型构建指南

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

问题描述

请根据以下 SEO 主题生成完整页面内容:

Title: QMT 基本面选股:基于杜邦分析法 (DuPont Analysis) 的因子模型

Question: 如何利用 QMT 的 get_financial_data 接口构建杜邦分析选股模型?

解决方案

QMT 基本面选股:基于杜邦分析法 (DuPont Analysis) 的因子模型

杜邦分析法(DuPont Analysis)是一种经典的财务分析框架,它将净资产收益率(ROE)拆解为三个核心驱动因子:

$$\text{ROE} = \text{净利润率 (Net Profit Margin)} \times \text{总资产周转率 (Asset Turnover)} \times \text{权益乘数 (Equity Multiplier)}$$

通过该模型,量化投资者可以判断企业高 ROE 是来自于产品高附加值(高净利润率)、高效运营(高周转率)还是高杠杆(高权益乘数),从而筛选出具备高质量盈利能力的标的。


1. QMT 财务数据接口说明

在 QMT 中,我们可以通过 ContextInfo.get_financial_data() 接口下载并读取本地财务数据。用到的主要财务报表及字段如下:

  • 利润表 (ASHAREINCOME): 净利润 (net_profit_incl_min_int_inc)、营业收入 (revenue_inc)
  • 资产负债表 (ASHAREBALANCESHEET): 资产总计 (tot_assets)、所有者权益合计 (total_equity)

2. 策略代码实现

以下策略展示了如何在 QMT 中基于杜邦分析法对股票池(如沪深300)进行多因子打分并定期调仓。

#coding:gbk
import pandas as pd
import numpy as np

def init(ContextInfo):
    # 1. 设置股票池为沪深300
    ContextInfo.stocks = ContextInfo.get_sector('000300.SH')
    ContextInfo.set_universe(ContextInfo.stocks)
    
    # 2. 定时器设置:每月运行一次杜邦分析选股(按 20 个交易日)
    ContextInfo.hold_days = 0
    ContextInfo.trade_cycle = 20
    ContextInfo.num_select = 10  # 最终选出的高质标的数量

def handlebar(ContextInfo):
    # 控制调仓周期
    if ContextInfo.hold_days % ContextInfo.trade_cycle != 0:
        ContextInfo.hold_days += 1
        return
    ContextInfo.hold_days += 1
    
    # 获取当前 K 线索引及交易日
    barpos = ContextInfo.barpos
    stocks = ContextInfo.stocks
    
    # 财务字段列表
    fields = [
        'ASHAREINCOME.net_profit_incl_min_int_inc', # 净利润
        'ASHAREINCOME.revenue_inc',                # 营业收入
        'ASHAREBALANCESHEET.tot_assets',           # 总资产
        'ASHAREBALANCESHEET.total_equity'          # 所有者权益
    ]
    
    # 取最近一个报告期的财务数据
    start_date = '20220101'
    end_date = '20231231'
    
    try:
        fin_df = ContextInfo.get_financial_data(fields, stocks, start_date, end_date, report_type='report_time') العامة
    except Exception as e:
        print("获取财务数据失败:", e)
        return
        
    # 提取最新的数据构建杜邦分析数据框
    # 计算杜邦三要素
    selected_stocks = []
    dupont_scores = {}
    
    for stock in stocks:
        try:
            # 获取该股票最新财报数据
            net_profit = ContextInfo.get_financial_data('ASHAREINCOME', 'net_profit_incl_min_int_inc', stock.split('.')[1], stock.split('.')[0], 'report_time', barpos)
            revenue = ContextInfo.get_financial_data('ASHAREINCOME', 'revenue_inc', stock.split('.')[1], stock.split('.')[0], 'report_time', barpos)
            tot_assets = ContextInfo.get_financial_data('ASHAREBALANCESHEET', 'tot_assets', stock.split('.')[1], stock.split('.')[0], 'report_time', barpos)
            total_equity = ContextInfo.get_financial_data('ASHAREBALANCESHEET', 'total_equity', stock.split('.')[1], stock.split('.')[0], 'report_time', barpos)
            
            if None in [net_profit, revenue, tot_assets, total_equity] or tot_assets == 0 or total_equity == 0 or revenue == 0:
                continue
                
            # 计算杜邦拆解指标
            net_margin = net_profit / revenue        # 净利润率
            asset_turnover = revenue / tot_assets     # 资产周转率
            equity_multiplier = tot_assets / total_equity # 权益乘数
            
            roe = net_margin * asset_turnover * equity_multiplier
            
            # 筛选条件:排除资产负债率过高(杠杆过高)的股票,偏好高利润率与高周转率驱动的企业
            if equity_multiplier < 3.0 and net_margin > 0.08:
                # 综合打分:高 ROE 且杠杆适中
                dupont_scores[stock] = roe
        except:
            continue
            
    # 按 ROE 得分排序,选择 Top N 股票
    sorted_stocks = sorted(dupont_scores.items(), key=lambda x: x[1], reverse=True)
    target_stocks = [stk[0] for stk in sorted_stocks[:ContextInfo.num_select]]
    
    print(f"【杜邦分析选股结果】选出标的: {target_stocks}")
    
    # 调仓逻辑:卖出非目标股,买入目标股
    account = '6000000248' # 请替换为真实或模拟账号
    for stock in ContextInfo.stocks:
        if stock not in target_stocks:
            # 调仓卖出
            order_target_value(stock, 0, ContextInfo, account)
            
    # 等权重买入选出标的
    target_weight = 1.0 / len(target_stocks) if target_stocks else 0
    for stock in target_stocks:
        order_target_percent(stock, target_weight, ContextInfo, account)

3. 注意事项与优化方向

  1. 数据补充:在运行该策略前,请确保已通过 QMT 客户端的 “数据管理” 补全对应标的的资产负债表与利润表等历史财务数据。
  2. 剔除高杠杆陷阱:在策略逻辑中加入 equity_multiplier < 3.0,可以有效规避通过盲目放大负债提升 ROE 的风险公司。
  3. 结合估值因子:建议配合 Valuation_and_Market_Cap.PEPB 因子进行二次筛选,避免买入基本面优良但估值过高的股票。