3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
杜邦分析法(DuPont Analysis)是一种经典的财务分析框架,它将净资产收益率(ROE)拆解为三个核心驱动因子:
$$\text{ROE} = \text{净利润率 (Net Profit Margin)} \times \text{总资产周转率 (Asset Turnover)} \times \text{权益乘数 (Equity Multiplier)}$$
通过该模型,量化投资者可以判断企业高 ROE 是来自于产品高附加值(高净利润率)、高效运营(高周转率)还是高杠杆(高权益乘数),从而筛选出具备高质量盈利能力的标的。
在 QMT 中,我们可以通过 ContextInfo.get_financial_data() 接口下载并读取本地财务数据。用到的主要财务报表及字段如下:
ASHAREINCOME): 净利润 (net_profit_incl_min_int_inc)、营业收入 (revenue_inc)ASHAREBALANCESHEET): 资产总计 (tot_assets)、所有者权益合计 (total_equity)以下策略展示了如何在 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)
equity_multiplier < 3.0,可以有效规避通过盲目放大负债提升 ROE 的风险公司。Valuation_and_Market_Cap.PE 或 PB 因子进行二次筛选,避免买入基本面优良但估值过高的股票。