3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
这是一个结合了**估值因子(PE)和动量因子(20日涨跌幅)**的多因子选股策略。
Valuation_and_Market_Cap.PE。逻辑是低估值优先(PE越小越好)。Trend.REVS20。逻辑是动量效应(过去20日涨幅越高越好)。# -*- coding: gbk -*-
import pandas as pd
import numpy as np
def init(ContextInfo):
"""
策略初始化函数
"""
# 1. 策略参数设置
ContextInfo.target_num = 20 # 持仓股票数量
ContextInfo.benchmark = '000300.SH' # 股票池基准(沪深300)
ContextInfo.account_id = '600000248' # 请修改为您的资金账号
# 2. 设置账号
ContextInfo.set_account(ContextInfo.account_id)
# 3. 设置股票池
# 获取沪深300成分股
stock_list = ContextInfo.get_sector(ContextInfo.benchmark)
ContextInfo.set_universe(stock_list)
# 4. 调仓控制变量
ContextInfo.last_month = -1 # 用于记录上一次调仓的月份
def handlebar(ContextInfo):
"""
K线周期运行函数
"""
# 1. 获取当前时间
# get_bar_timetag 返回的是毫秒时间戳
timetag = ContextInfo.get_bar_timetag(ContextInfo.barpos)
# 转换为日期字符串 YYYYMMDD
current_date_str = timetag_to_datetime(timetag, '%Y%m%d')
# 获取当前月份
current_month = int(current_date_str[4:6])
# 2. 判断是否换月(简单的月度调仓逻辑)
if current_month == ContextInfo.last_month:
return
# 更新月份记录
ContextInfo.last_month = current_month
print(f'触发调仓,当前日期: {current_date_str}')
# 3. 获取因子数据
# 使用 QMT 内置的多因子库
# Valuation_and_Market_Cap.PE : 市盈率
# Trend.REVS20 : 20日价格动量
factor_fields = ['Valuation_and_Market_Cap.PE', 'Trend.REVS20']
stock_list = ContextInfo.get_universe()
# 获取当天的因子数据
# 注意:get_factor_data 返回的数据格式取决于参数。
# 传入股票列表和单日时间,返回 DataFrame (Index=股票代码, Columns=因子名)
df_factors = ContextInfo.get_factor_data(
factor_fields,
stock_list,
current_date_str,
current_date_str
)
if df_factors is None or df_factors.empty:
print("未获取到因子数据,跳过本次调仓")
return
# 4. 数据清洗与打分
# 去除空值
df_factors.dropna(inplace=True)
# 过滤掉 PE 为负(亏损)的股票,通常估值策略只看正PE
df_factors = df_factors[df_factors['Valuation_and_Market_Cap.PE'] > 0]
if df_factors.empty:
return
# 计算排名 (Rank)
# PE: 升序排名 (值越小排名越靠前,rank值越小)
df_factors['rank_pe'] = df_factors['Valuation_and_Market_Cap.PE'].rank(ascending=True)
# 动量: 降序排名 (值越大排名越靠前,rank值越小)
df_factors['rank_mom'] = df_factors['Trend.REVS20'].rank(ascending=False)
# 计算综合得分 (等权重相加)
df_factors['score'] = df_factors['rank_pe'] + df_factors['rank_mom']
# 按得分升序排列 (分数越低越好)
df_factors.sort_values(by='score', ascending=True, inplace=True)
# 选取前 N 只股票
target_list = df_factors.head(ContextInfo.target_num).index.tolist()
print(f"选股结果: {target_list}")
# 5. 交易执行
# 计算单只股票的目标权重 (等权重)
if len(target_list) > 0:
target_weight = 1.0 / len(target_list)
else:
target_weight = 0.0
# 获取当前持仓
positions = get_trade_detail_data(ContextInfo.account_id, 'stock', 'position')
holding_list = [obj.m_strInstrumentID for obj in positions]
# 卖出逻辑:不在目标列表中的股票,权重设为0(清仓)
for code in holding_list:
if code not in target_list:
order_target_percent(code, 0, ContextInfo, ContextInfo.account_id)
# 买入/调仓逻辑:在目标列表中的股票,调整至目标权重
for code in target_list:
order_target_percent(code, target_weight, ContextInfo, ContextInfo.account_id)
get_factor_data 接口:
Valuation_and_Market_Cap.PE 对应市盈率。Trend.REVS20 对应20日收益率(动量)。rank 排序)。打分逻辑:
rank() 函数将绝对数值转换为相对排名。这消除了不同因子量纲(PE是几十倍,动量是百分比)不一致的问题。ascending=True。ascending=False。交易执行:
order_target_percent 函数。这是一个非常方便的高级交易函数,它会自动计算当前持仓与目标仓位的差额,并发出相应的买入或卖出指令。例如,如果目标权重是 5%,当前持有 2%,它会自动买入 3%。数据清洗:
df_factors.dropna() 和 PE > 0 的过滤,这是量化实盘中防止脏数据导致报错或买入亏损股的必要步骤。Q: 如何查看 QMT 支持的所有因子名称?
A: 在 QMT 软件界面的“帮助”文档中,或者在策略编辑器中查看“多因子库”部分。文档附录通常有详细的因子表名和字段名对照表(如 Valuation_and_Market_Cap 表下的 PE)。
Q: 为什么使用 order_target_percent 而不是 passorder?
A: passorder 是底层的下单接口,需要自己计算买卖数量。对于选股策略,我们通常关注的是“仓位占比”,order_target_percent 封装了计算逻辑,能自动处理买卖方向和数量,代码更简洁且不易出错。
Q: 这个策略可以在回测和实盘中直接运行吗?
A: 可以。但请注意:
ContextInfo.account_id 需要修改为你实际的资金账号。get_factor_data 将无法返回结果。