聚宽如何筛选出每月涨幅最大的前10只基金
各路大神,刚入坑聚宽,我想按照基金每月的涨幅排名,取涨幅最大的前10只,然后下月第一个工作日买入,做一个量化回测。前提是需要筛选出符合条件的基金,请问聚宽有对应的函数或者好的方法吗?一个聚宽的小白,期待您的回答,万分感谢!
问题描述
解决方案
在聚宽(JoinQuant)平台上实现“每月筛选涨幅最大的前10只基金并在下月第一个工作日买入”的策略,主要分为以下几个步骤:
- 确定基金池:通常量化回测中交易的是场内基金(ETF、LOF等),因为它们像股票一样在交易所实时交易。
- 定时运行:使用
run_monthly函数设定在每月第一个交易日执行调仓逻辑。 - 获取历史数据并计算涨幅:使用
history函数获取过去一个月(约21个交易日)的收盘价,计算涨幅。 - 排序与调仓:根据涨幅降序排列,取前10只基金,卖出不在名单中的持仓,等权重买入这10只基金。
以下是完整的策略源码,你可以直接复制到聚宽的策略研究环境中进行回测:
# 导入聚宽函数库
import jqdata
import pandas as pd
# 初始化函数,设定基准等等
def initialize(context):
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 过滤掉order系列API产生的比error级别低的log
log.set_level('order', 'error')
# 设定场内基金的交易费率:买入0.03%,卖出0.03%,免印花税,最低5元
set_order_cost(OrderCost(close_tax=0, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='fund')
# 设定每月第一个交易日的 09:30 运行调仓函数
run_monthly(trade, monthday=1, time='09:30')
# 核心调仓逻辑
def trade(context):
# 1. 获取场内基金列表(这里以 ETF 和 LOF 为例)
# get_all_securities 可以获取指定类型的标的
df_funds = get_all_securities(['etf', 'lof'])
fund_list = list(df_funds.index)
# 2. 获取过去21个交易日(约一个月)的收盘价数据
# df=True 返回 pandas.DataFrame 格式,方便计算
h_data = history(count=21, unit='1d', field='close', security_list=fund_list, df=True)
# 3. 数据清洗与涨幅计算
# 剔除掉包含 NaN 的列(即上市不足一个月或停牌的基金)
h_data = h_data.dropna(axis=1)
if h_data.empty:
return
# 计算涨幅:(期末价格 - 期初价格) / 期初价格
returns = (h_data.iloc[-1] - h_data.iloc[0]) / h_data.iloc[0]
# 4. 排序并获取涨幅最大的前10只基金
top10_funds = returns.sort_values(ascending=False).head(10).index.tolist()
log.info(f"本月选出的前10只基金为:{top10_funds}")
# 5. 执行交易调仓
# 5.1 卖出不在 top10 列表中的现有持仓
for security in list(context.portfolio.positions.keys()):
if security not in top10_funds:
order_target(security, 0)
# 5.2 等权重买入 top10 基金
if len(top10_funds) > 0:
# 计算每只基金应分配的资金(总资产 / 10)
target_value = context.portfolio.total_value / len(top10_funds)
for security in top10_funds:
order_target_value(security, target_value)
代码原理解析:
get_all_securities(['etf', 'lof']):获取聚宽平台上所有的 ETF 和 LOF 基金代码。如果你只想做 ETF 轮动,可以改为['etf']。history(21, '1d', 'close', ...):获取过去21天的收盘价。21天大约是一个月的交易日天数。返回的 DataFrame 行是日期,列是基金代码。h_data.dropna(axis=1):这一步非常重要,它可以过滤掉那些刚上市不久(没有21天数据)或者期间长期停牌导致数据缺失的基金,避免计算报错。order_target_value(security, target_value):将指定标的的仓位调整到目标价值。如果当前没持有,就会买入;如果持有但价值不够,会补仓;如果超出了,会减仓。这比手动计算买入股数要方便得多。
进阶建议:
- 流动性过滤:有些冷门基金成交量极低,实盘中可能买不进去。你可以结合
history获取volume或money(成交额),在计算涨幅前把日均成交额低于 1000 万的基金剔除。 - 动量崩溃防范:纯粹追涨杀跌在熊市可能会遭遇大幅回撤。可以加入一个大盘择时条件(例如沪深300跌破20日均线时全部空仓),或者要求基金本身的涨幅必须大于0才买入。