3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
季末弱基回补策略的核心逻辑在于:部分基金在季度末由于机构调仓、赎回压力或 window dressing(橱窗粉饰)效应,导致净值短期内出现非理性下跌(表现较弱)。而在新季度开始后,随着资金回流和市场情绪修复,这些被超卖的弱势基金大概率会迎来估值修复(回补)。
在聚宽(JoinQuant)平台上,我们可以通过以下步骤实现该策略:
get_all_securities(['etf', 'lof']):获取所有上市基金列表。get_price(security, start_date, end_date, fields=['close']):获取基金历史收盘价以计算季度收益率。run_monthly(func, monthday, time):设定在特定月份的特定交易日运行筛选与交易逻辑。以下是基于聚宽 API 编写的完整策略代码:
import pandas as pd
import numpy as np
from jqdata import *
def initialize(context):
# 设定基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 设定初始资金与手续费
set_order_cost(OrderCost(open_commission=0.0003, close_commission=0.0003, min_commission=5), type='fund')
# 定义全局变量
g.buy_list = []
g.hold_days = 0
g.max_hold_days = 10 # 新季度开始后持有10个交易日
# 运行函数:每月倒数第5个交易日运行筛选逻辑(季末月为3, 6, 9, 12)
run_monthly(check_weak_funds, monthday=-5, time='9:30')
# 每日运行检查卖出逻辑
run_daily(market_open, time='every_bar')
def check_weak_funds(context):
# 仅在季末月(3, 6, 9, 12月)进行筛选
current_month = context.current_dt.month
if current_month not in [3, 6, 9, 12]:
return
log.info(f"进入季末月 {current_month},开始筛选弱势基金...")
# 获取所有上市ETF和LOF基金
funds = list(get_all_securities(['etf', 'lof'], date=context.current_dt.date()).index)
# 获取过去60个交易日(约一个季度)的基金价格数据
end_date = context.previous_date
hist = get_price(funds, count=60, end_date=end_date, frequency='daily', fields=['close'], panel=False)
# 计算每只基金过去一季度的收益率
returns = {}
for fund in funds:
fund_data = hist[hist['code'] == fund]
if len(fund_data) >= 60:
close_prices = fund_data['close'].values
ret = (close_prices[-1] - close_prices[0]) / close_prices[0]
returns[fund] = ret
# 转换为 Series 并排序,找出表现最弱(跌幅最大)的前5只基金
returns_series = pd.Series(returns).sort_values()
g.buy_list = list(returns_series.head(5).index)
log.info(f"筛选出的季末弱势基金为: {g.buy_list}")
def market_open(context):
# 1. 卖出逻辑:如果持有达到最大持有天数,则平仓
if g.hold_days >= g.max_hold_days:
for fund in list(context.portfolio.positions.keys()):
order_target(fund, 0)
log.info(f"持有期满,卖出基金: {fund}")
g.hold_days = 0
g.buy_list = [] # 清空买入列表
# 2. 买入逻辑:在季末倒数第1个交易日买入
# 此处简化为:当g.buy_list不为空,且当前账户未持仓时,在季末最后几天全仓买入
if g.buy_list and len(context.portfolio.positions) == 0:
# 检查是否是季末的最后两个交易日
# 简单起见,在筛选出弱势基金后,下一个交易日直接买入
cash = context.portfolio.available_cash
if cash > 0:
value_per_fund = cash / len(g.buy_list)
for fund in g.buy_list:
order_value(fund, value_per_fund)
log.info(f"买入弱势基金: {fund}, 金额: {value_per_fund}")
g.hold_days = 1
elif len(context.portfolio.positions) > 0:
# 如果已持仓,每日累加持有天数
g.hold_days += 1