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

如何在聚宽平台编写 ETF 日内轮动策略?(实现动量筛选、分散持仓与先卖后买)

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

问题描述

聚宽 ETF T+0 日内轮动:如何实现动态仓位与分散持仓?
如何用聚宽编写 ETF 日内轮动策略,实现动量筛选、分散持仓和先卖后买的仓位管理?

解决方案

聚宽 ETF T+0 日内轮动策略实现方案

在构建 ETF 日内轮动策略时,核心在于规避未来函数合理分配资金(分散持仓)以及在有限资金下通过“先卖后买”释放流动性。此外,由于 A 股 ETF 具备 T+0 交易特性,我们需要在聚宽中开启实验性的 T+0 模式。

以下是完整的策略设计与 Python 源码实现:

1. 核心设计思路

  • 动态复权与 T+0 模式:在 initialize 中通过 set_option('use_real_price', True) 开启真实价格模式,并使用 set_option('t0_mode', True) 允许日内买入后立刻卖出。
  • 动量筛选:利用 history 获取候选 ETF 过去 5 天的收盘价,计算涨幅并降序排列,筛选出涨幅最高的前 $N$ 只 ETF。
  • 分散持仓:将总资产均分为 $N$ 份,每只入选 ETF 分配等额的资金预算。
  • 先卖后买:在调仓执行阶段,必须先遍历并执行卖出不再满足条件的持仓,释放可用现金(available_cash)后,再执行买入逻辑,防止因资金占用导致买入失败。

2. 策略源码 (Python 3)

# 导入聚宽函数库
import jqdata
import pandas as pd
import numpy as np

def initialize(context):
    # 1. 设定沪深300作为基准
    set_benchmark('000300.XSHG')
    # 2. 开启真实价格模式(动态复权)
    set_option('use_real_price', True)
    # 3. 开启 T+0 交易模式(允许日内回转交易)
    set_option('t0_mode', True)
    
    # 设定交易费率:ETF 佣金万分之三,无印花税,最低5元
    set_order_cost(OrderCost(open_tax=0, close_tax=0, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='fund')
    
    # 策略参数设置
    g.etf_pool = [
        '510300.XSHG', # 300ETF
        '510500.XSHG', # 500ETF
        '518880.XSHG', # 黄金ETF
        '159915.XSHE', # 创业板ETF
        '513100.XSHG', # 纳指ETF
        '510050.XSHG'  # 50ETF
    ]
    g.hold_num = 3  # 同时分散持仓的 ETF 数量
    g.momentum_window = 5  # 动量计算窗口(天)
    
    # 每日 14:50 进行日内轮动调仓(避开开盘剧烈波动,并在收盘前完成轮动)
    run_daily(handle_rotation, time='14:50')

def handle_rotation(context):
    # 获取当前持仓列表
    current_positions = list(context.portfolio.positions.keys())
    
    # 1. 动量筛选:获取过去 5 天的收盘价(不含今天)
    hist_data = history(g.momentum_window + 1, unit='1d', field='close', security_list=g.etf_pool, df=True)
    
    # 计算 5 日变化率
    returns = (hist_data.iloc[-1] - hist_data.iloc[0]) / hist_data.iloc[0]
    # 降序排列并筛选前 N 只
    target_etfs = list(returns.sort_values(ascending=False).index[:g.hold_num])
    
    log.info(f"今日目标持仓 ETF: {target_etfs}")
    
    # 2. 先卖后买逻辑:释放资金
    # 找出需要清仓的 ETF
    to_sell = [etf for etf in current_positions if etf not in target_etfs]
    for etf in to_sell:
        order_target(etf, 0)
        log.info(f"[先卖] 清仓未入选 ETF: {etf}")
        
    # 3. 动态计算买入仓位
    # 卖出执行后,获取最新总资产,计算单只 ETF 预算
    total_value = context.portfolio.total_value
    single_budget = total_value / g.hold_num
    
    # 4. 执行买入/调仓
    for etf in target_etfs:
        # 目标是使该 ETF 的持仓价值达到 single_budget
        order_target_value(etf, single_budget)
        log.info(f"[后买] 调整目标持仓价值: {etf} -> 预算: {single_budget:.2f}元")

def after_trading_end(context):
    # 每日收盘后打印持仓详情
    log.info("每日收盘持仓详情:")
    for security, position in context.portfolio.positions.items():
        log.info(f"标的: {security}, 总仓位: {position.total_amount}, 价值: {position.value:.2f}元")

3. 关键 API 提示

  • set_option('t0_mode', True):此实验性设置允许在回测和模拟盘中,买入的 A 股或 ETF 在当天即可卖出,完美契合日内 T+0 轮动需求。
  • order_target_value(security, value):直接将标的仓位调整至目标价值。配合“先卖后买”流程,能自动计算补仓或减仓额度,极大地简化了分散持仓的比例控制代码。