3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
这是一个基于QMT平台的动量策略实现。
init 中修改)。# -*- coding: gbk -*-
import pandas as pd
import numpy as np
def init(ContextInfo):
"""
初始化函数,设定股票池、账号、全局变量
"""
# 1. 设定基准和股票池(这里以沪深300为例)
ContextInfo.index_code = '000300.SH'
ContextInfo.set_universe(ContextInfo.get_stock_list_in_sector('沪深300'))
# 2. 设定资金账号 (请替换为您自己的资金账号)
ContextInfo.accID = 'YOUR_ACCOUNT_ID'
ContextInfo.set_account(ContextInfo.accID)
# 3. 初始化全局变量
ContextInfo.last_month = None # 用于记录上一次调仓的月份
ContextInfo.holdings = [] # 记录当前持仓
print("策略初始化完成")
def get_momentum_stocks(ContextInfo):
"""
计算动量并筛选前10%的股票
"""
stock_list = ContextInfo.get_universe()
# 获取过去约3个月(60个交易日)的历史收盘价数据
# count=61 是为了保证能计算出60天的涨幅 (今天 / 60天前 - 1)
data_map = ContextInfo.get_market_data_ex(
['close'],
stock_list,
period='1d',
count=61,
dividend_type='front' # 前复权
)
momentum_dict = {}
for stock in stock_list:
if stock in data_map:
df = data_map[stock]
# 确保数据长度足够计算
if len(df) >= 60:
# 获取最新收盘价和60天前的收盘价
price_now = df.iloc[-1]['close']
price_prev = df.iloc[0]['close'] # 取获取到的数据的第一条作为基准
if price_prev > 0:
# 计算收益率
ret = (price_now - price_prev) / price_prev
momentum_dict[stock] = ret
# 按收益率从高到低排序
sorted_stocks = sorted(momentum_dict.items(), key=lambda x: x[1], reverse=True)
# 选取前10%
select_count = int(len(sorted_stocks) * 0.1)
if select_count < 1:
select_count = 1
target_stocks = [x[0] for x in sorted_stocks[:select_count]]
return target_stocks
def rebalance(ContextInfo, target_stocks):
"""
调仓执行函数
"""
print(f"开始调仓,目标持仓数量: {len(target_stocks)}")
# 1. 获取当前持仓
# 注意:回测模式下可以直接读取 ContextInfo.holdings (如果自己维护)
# 或者使用 get_trade_detail_data 获取真实/模拟账户持仓
positions = get_trade_detail_data(ContextInfo.accID, 'stock', 'position')
current_holdings = [obj.m_strInstrumentID + '.' + obj.m_strExchangeID for obj in positions]
# 2. 卖出不在目标池中的股票
for stock in current_holdings:
if stock not in target_stocks:
# 目标仓位为0,即清仓
order_target_percent(stock, 0, 'fix', -1, ContextInfo, ContextInfo.accID)
print(f"卖出平仓: {stock}")
# 3. 买入目标池中的股票
if len(target_stocks) > 0:
# 等权重分配,每个股票分配 1/N 的资金
weight = 1.0 / len(target_stocks)
for stock in target_stocks:
# 目标仓位调整为 weight (例如 0.05 代表 5%)
# 注意:order_target_percent 需要在回测或实盘支持该接口的环境下运行
# 如果是纯实盘简易模式,可能需要改用 order_target_value
order_target_percent(stock, weight, 'fix', -1, ContextInfo, ContextInfo.accID)
print(f"买入/调整: {stock}, 目标权重: {weight:.2%}")
def handlebar(ContextInfo):
"""
K线周期运行函数
"""
# 获取当前K线的时间
index = ContextInfo.barpos
timetag = ContextInfo.get_bar_timetag(index)
current_date_str = timetag_to_datetime(timetag, '%Y%m%d')
current_month = current_date_str[0:6] # 提取 'YYYYMM'
# 判断是否是新的一月
if ContextInfo.last_month != current_month:
print(f"检测到新月份: {current_month},触发调仓逻辑...")
# 1. 选股
target_stocks = get_momentum_stocks(ContextInfo)
# 2. 执行调仓
rebalance(ContextInfo, target_stocks)
# 3. 更新月份记录
ContextInfo.last_month = current_month
ContextInfo.get_market_data_ex:
count=61:我们需要计算过去60个交易日的涨幅,所以取61根K线,用 (第61根收盘价 - 第1根收盘价) / 第1根收盘价 来计算。dividend_type='front':使用前复权数据,这对于计算长周期收益率至关重要,可以避免分红除权导致的价格跳水误判。调仓时间控制:
current_month 和 ContextInfo.last_month 来判断是否换月。交易函数 order_target_percent:
weight = 1.0 / len(target_stocks) 实现了等权重买入。order_target_percent(stock, 0, ...) 进行平仓。账号设置:
ContextInfo.accID = 'YOUR_ACCOUNT_ID' 处需要您填入实际的资金账号(回测时通常不需要改,实盘/模拟盘必须填对)。get_market_data_ex 可能返回空值。Q: 如何修改回测的起止时间?
A: 在QMT策略编辑器的右侧“回测参数”面板中直接设置“开始时间”和“结束时间”,或者在代码 init 函数中添加 ContextInfo.start = '2020-01-01' 和 ContextInfo.end = '2021-01-01'。
Q: 为什么回测时没有交易?
A: 1. 检查是否下载了对应的历史数据。2. 检查 ContextInfo.accID 是否设置正确(回测模式下通常会自动分配虚拟账号,但显式设置为空字符串 '' 有时更安全)。3. 检查 get_stock_list_in_sector 获取的板块名称是否正确。
Q: 如何将选股范围改为全市场?
A: 将 init 中的 ContextInfo.set_universe(...) 替换为 ContextInfo.set_universe(ContextInfo.get_stock_list_in_sector('沪深A股'))。注意全市场选股计算量较大,回测速度会变慢。