3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
这是一个基于 QMT 平台的投资组合再平衡策略(Portfolio Rebalancing Strategy)。
init 中设定一个目标投资组合及其对应的权重(例如:60% 股票A,40% 股票B)。handlebar 中,根据设定的周期(如每月第一个交易日)触发调仓逻辑。order_target_percent 函数。该函数会自动计算当前持仓价值与目标价值的差额,并自动下单买入或卖出,使该标的占总资产的比例达到预设值。# -*- coding: gbk -*-
import pandas as pd
def init(ContextInfo):
"""
初始化函数,设定账户、股票池、目标权重和调仓周期
"""
# 1. 设置资金账号 (请替换为您真实的资金账号)
ContextInfo.account_id = 'YOUR_ACCOUNT_ID'
ContextInfo.account_type = 'STOCK' # 账号类型:STOCK-股票,FUTURE-期货
ContextInfo.set_account(ContextInfo.account_id)
# 2. 设定目标投资组合及权重 (权重之和建议为 1.0)
# 示例:贵州茅台 40%, 宁德时代 30%, 五粮液 30%
ContextInfo.target_weights = {
'600519.SH': 0.4,
'300750.SZ': 0.3,
'000858.SZ': 0.3
}
# 3. 设置股票池 (用于回测时下载数据)
ContextInfo.set_universe(list(ContextInfo.target_weights.keys()))
# 4. 策略运行参数
ContextInfo.rebalance_period = 'monthly' # 调仓周期: 'monthly' (月度) 或 'weekly' (周度)
ContextInfo.last_rebalance_date = None # 记录上次调仓日期
print("策略初始化完成,目标组合权重:", ContextInfo.target_weights)
def handlebar(ContextInfo):
"""
行情驱动函数,每根K线运行一次
"""
# 获取当前K线的时间
index = ContextInfo.barpos
timetag = ContextInfo.get_bar_timetag(index)
current_date_str = timetag_to_datetime(timetag, '%Y%m%d')
# 检查是否需要调仓
if not check_rebalance_condition(ContextInfo, current_date_str):
return
print(f"[{current_date_str}] 触发再平衡调仓...")
# 执行调仓逻辑
rebalance_portfolio(ContextInfo)
# 更新上次调仓时间
ContextInfo.last_rebalance_date = current_date_str
def check_rebalance_condition(ContextInfo, current_date_str):
"""
判断是否满足调仓时间条件
"""
# 如果是第一天运行,直接调仓
if ContextInfo.last_rebalance_date is None:
return True
last_date = ContextInfo.last_rebalance_date
# 月度调仓:判断当前月份是否与上次调仓月份不同
if ContextInfo.rebalance_period == 'monthly':
current_month = current_date_str[0:6] # 取 YYYYMM
last_month = last_date[0:6]
if current_month != last_month:
return True
# 周度调仓:这里简单判断是否跨周(实际应用可结合 datetime 库判断周几)
# 为了演示简单,此处仅实现月度逻辑,如需周度可扩展
return False
def rebalance_portfolio(ContextInfo):
"""
执行核心调仓逻辑
"""
# 1. 获取当前账户的总资产 (用于计算目标持仓市值,但在 order_target_percent 中通常自动处理)
# 注意:order_target_percent 是基于账户总资产(现金+市值)计算比例
# 2. 遍历目标权重字典进行调仓
for stock_code, target_weight in ContextInfo.target_weights.items():
# 获取当前标的最新价,用于日志输出或检查停牌
last_price = ContextInfo.get_market_data_ex(
['close'], [stock_code], period=ContextInfo.period, count=1
)
if stock_code in last_price and not last_price[stock_code].empty:
# 使用 order_target_percent 函数
# 该函数会自动计算:(总资产 * target_weight) / 股价 = 目标股数
# 然后自动下单买入或卖出差额
order_target_percent(
stock_code,
target_weight,
ContextInfo,
ContextInfo.account_id
)
print(f" -> 调整 {stock_code} 仓位至目标权重: {target_weight*100}%")
else:
print(f" -> 警告: 无法获取 {stock_code} 行情,跳过调仓")
# 3. (可选) 清理不在目标列表中的持仓
# 如果您希望卖出所有不在 target_weights 中的股票,需要获取当前持仓并遍历
# 此处为简易版,仅处理 target_weights 中定义的股票
order_target_percent:
调仓时间控制 (check_rebalance_condition):
handlebar 中,我们通过比较当前 K 线日期的月份和上一次调仓日期的月份。数据获取:
get_market_data_ex 来简单检查行情是否存在,防止对停牌或无数据的股票下单导致报错。YOUR_ACCOUNT_ID 替换为您真实的资金账号。ContextInfo.target_weights 中修改您想要的股票代码和权重。Q: 如果我想把某只股票彻底清仓怎么办?
A: 在 ContextInfo.target_weights 中将该股票的权重设置为 0.0,策略在下次调仓时会调用 order_target_percent(code, 0, ...),从而卖出该股票的所有持仓。
Q: order_target_percent 是按什么价格下单的?
A: 默认情况下,QMT 的交易函数在回测中通常以当前 K 线的收盘价(或次日开盘价,取决于回测机制设置)成交。在实盘中,如果不指定 style 和 price 参数,通常默认以最新价(LATEST)下单。如果需要指定限价或对手价,可以在函数中增加参数,例如:order_target_percent(..., style='COMPETE', ...) 使用对手价。
Q: 为什么回测时第一天就买入了?
A: 代码逻辑中 if ContextInfo.last_rebalance_date is None: return True 确保了策略在开始运行的第一天就会进行一次建仓,将现金转换为股票组合。