🚀 AI 一键生成 joinquant 策略代码
立即体验

聚宽平台如何编写季末弱基回补策略?(附 Python 源码)

joinquant | 发布时间: 2026/8/12
以下内容由 EasyQuant 生成。

问题描述

聚宽如何编写季末弱基回补策略?
如何利用聚宽的行情和基金数据识别季末表现较弱但可能回补的基金,并设计相应的买卖规则?

解决方案

季末弱基回补策略逻辑设计

季末弱基回补策略的核心逻辑在于:部分基金在季度末由于机构调仓、赎回压力或 window dressing(橱窗粉饰)效应,导致净值短期内出现非理性下跌(表现较弱)。而在新季度开始后,随着资金回流和市场情绪修复,这些被超卖的弱势基金大概率会迎来估值修复(回补)。

在聚宽(JoinQuant)平台上,我们可以通过以下步骤实现该策略:

  1. 基金池筛选:选择流动性较好的上市基金(如ETF、LOF),避免场外基金申赎的T+2延迟。
  2. 弱势基金识别:在季末前(如3月、6月、9月、12月的倒数第5个交易日),计算基金在过去一个季度的累计收益率,找出跌幅最大(或表现最弱)的Top N只基金。
  3. 买卖规则
    • 买入:在季末倒数第1个交易日收盘前,买入识别出的弱势基金。
    • 卖出:在新季度开始后的第10个交易日(或达到预设止盈点)进行平仓,锁定回补收益。

聚宽 API 核心函数

  • get_all_securities(['etf', 'lof']):获取所有上市基金列表。
  • get_price(security, start_date, end_date, fields=['close']):获取基金历史收盘价以计算季度收益率。
  • run_monthly(func, monthday, time):设定在特定月份的特定交易日运行筛选与交易逻辑。

策略 Python 源码实现

以下是基于聚宽 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