3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
这是一个基于 日均换手率(Turnover Rate) 的选股策略。
# -*- coding: gbk -*-
import pandas as pd
import numpy as np
def init(ContextInfo):
# 1. 设置策略参数
ContextInfo.holding_num = 5 # 持仓股票数量
ContextInfo.lookback_days = 5 # 计算过去多少天的平均换手率
ContextInfo.index_code = '000300.SH' # 股票池:沪深300
# 2. 设置账号(请替换为您自己的资金账号)
# 格式如:'6000000248',如果是回测模式,这里会自动使用虚拟账号
ContextInfo.account_id = 'YOUR_ACCOUNT_ID'
ContextInfo.set_account(ContextInfo.account_id)
# 3. 设置回测参数(仅回测有效,实盘请在界面设置)
# 费率设置:万三
ContextInfo.set_commission(0, [0.0003, 0.0003, 0.0003, 0.0003, 0, 5])
# 滑点设置:0.02元
ContextInfo.set_slippage(1, 0.02)
def handlebar(ContextInfo):
# 仅在日线周期的每根K线结束或新K线开始时运行
# 这里我们选择在每根K线的第一个tick(即开盘)进行判断和交易
if not ContextInfo.is_new_bar():
return
# 1. 获取当前时间
barpos = ContextInfo.barpos
timetag = ContextInfo.get_bar_timetag(barpos)
current_date = timetag_to_datetime(timetag, '%Y%m%d')
print(f'当前交易日期: {current_date}')
# 2. 获取股票池(沪深300成分股)
# 注意:get_sector 获取的是当前成分股,回测中若需历史成分股需用 get_sector(code, timetag)
stock_list = ContextInfo.get_sector(ContextInfo.index_code, timetag)
if not stock_list:
print("未获取到成分股信息")
return
# 3. 获取交易日列表,用于确定计算换手率的时间窗口
# 获取包括当前日期在内的过去 lookback_days + 5 天的交易日,确保数据足够
# 我们需要用过去的数据来决策,所以截止日期是“昨天”
trading_dates = ContextInfo.get_trading_dates(stock_list[0], '', current_date, ContextInfo.lookback_days + 1, '1d')
if len(trading_dates) < ContextInfo.lookback_days + 1:
print("历史数据不足,跳过")
return
# 取过去N天(不包含今天,因为今天要根据过去的数据下单)
start_date = trading_dates[0]
end_date = trading_dates[-2] # 昨天的日期
# 4. 获取换手率数据
# get_turnover_rate 返回的是 DataFrame,Index为日期,Columns为股票代码
df_turnover = ContextInfo.get_turnover_rate(stock_list, start_date, end_date)
if df_turnover.empty:
print("未获取到换手率数据")
return
# 5. 计算平均换手率并排序
# 计算每只股票的均值
mean_turnover = df_turnover.mean()
# 降序排列
sorted_stocks = mean_turnover.sort_values(ascending=False)
# 取前 N 只
target_stocks = sorted_stocks.head(ContextInfo.holding_num).index.tolist()
print(f"今日选股: {target_stocks}")
# 6. 交易执行
# 获取当前持仓
positions = get_trade_detail_data(ContextInfo.account_id, 'stock', 'position')
current_holdings = [obj.m_strInstrumentID for obj in positions if obj.m_nVolume > 0]
# 6.1 卖出不在目标列表中的股票
for stock in current_holdings:
if stock not in target_stocks:
# 目标比例设为0,即清仓
order_target_percent(stock, 0, 'fix', -1, ContextInfo, ContextInfo.account_id)
print(f"卖出: {stock}")
# 6.2 买入/调整目标股票
# 等权重分配,每只股票目标仓位 = 1 / 持仓数量
target_weight = 1.0 / ContextInfo.holding_num
for stock in target_stocks:
# 使用 order_target_percent 自动调整仓位到目标比例
# 价格类型 'fix' 和价格 -1 在 order_target_percent 中通常代表以市价或最新价成交(视具体回测撮合设置)
# 实盘中建议根据盘口价格指定,这里演示简化处理
order_target_percent(stock, target_weight, 'fix', -1, ContextInfo, ContextInfo.account_id)
print(f"买入/调仓: {stock} 目标权重: {target_weight}")
数据获取 (get_turnover_rate):
ContextInfo.get_turnover_rate,这比手动用成交量除以流通股本更方便且准确。时间窗口处理:
ContextInfo.get_trading_dates 获取交易日历,取 trading_dates[-2] 作为数据截止日期(即昨天),避免用到今天的未来数据(Look-ahead bias)。交易函数 (order_target_percent):
股票池 (get_sector):
000300.SH (沪深300) 作为基础池。传入 timetag 参数是为了在回测时获取当时的历史成分股,防止幸存者偏差。init 函数中的 ContextInfo.account_id 为您的真实资金账号(如果是模拟/回测,QMT会自动分配,但建议显式设置)。get_turnover_rate 返回的数据中,停牌期间通常为 NaN 或 0。mean() 计算时会自动忽略 NaN,但如果某只股票长期停牌,换手率为 0,自然会被排序过滤掉,符合策略逻辑。ContextInfo.get_market_data_ex 获取实时行情来指定更精确的委托价格(如对手价、买一卖一价),而不是简单的使用默认价格。Q: 如何将股票池改为全市场股票?
A: 可以将 ContextInfo.index_code 修改为 '沪深A股',并使用 ContextInfo.get_stock_list_in_sector('沪深A股') 来获取全市场代码。但请注意,全市场计算量较大,回测速度会变慢。
Q: 为什么使用 order_target_percent 而不是 order_lots?
A: order_target_percent 更适合这种定期调仓的策略。它能自动根据当前总资产计算需要买入多少股,并且自动处理卖出逻辑(比如从持仓 1000 股调整到 0 股),大大简化了代码逻辑。
Q: 换手率数据需要额外下载吗?
A: 是的。QMT 的基础行情数据通常包含开高低收和成交量,但换手率可能涉及财务数据(流通股本)。建议在【数据管理】中同时补充【日线数据】和【财务数据】。