问题描述
解决方案
编写一个基于宏观经济数据(如 CPI)的择时策略,核心在于利用 JoinQuant 的宏观数据接口 (macro.run_query) 获取历史 CPI 数据,并根据通胀水平来调整仓位。
策略逻辑设计
- 核心假设:
- 高通胀(CPI 过高):通常意味着央行可能加息或收紧流动性,利空股市。策略选择空仓或减仓。
- 低/温和通胀(CPI 较低):通常意味着货币政策宽松或经济运行平稳,利好股市。策略选择满仓或买入。
- 标的:沪深300 ETF(例如
510300.XSHG)作为指数基金代表。 - 阈值设定:假设 CPI 同比增长率(YoY)超过 3% 为高通胀警戒线(此阈值可根据回测结果调整)。
- 调仓频率:CPI 数据通常按月发布,因此策略按月运行。
策略代码实现
以下是完整的策略代码,可以直接在聚宽的回测环境中运行。
# -*- coding: utf-8 -*-
from jqdata import *
def initialize(context):
"""
初始化函数,设定基准、标的、参数等
"""
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 过滤掉order系列API产生的比error级别低的log
log.set_level('order', 'error')
# 设定操作标的:华泰柏瑞沪深300ETF
g.security = '510300.XSHG'
# 设定CPI阈值,当CPI同比 > 3.0% 时认为通胀过高,卖出
g.cpi_threshold = 3.0
# 设定按月运行,每月第一个交易日进行判断
run_monthly(trade_func, monthday=1, time='open')
def trade_func(context):
"""
交易函数:获取宏观数据并执行交易
"""
# 1. 获取最新的CPI数据
# 查询宏观数据表 macro.MAC_CPI_MONTH
# 按统计月份倒序排列,取第一条(即离当前时间最近的一条已发布数据)
q = query(
macro.MAC_CPI_MONTH
).order_by(
macro.MAC_CPI_MONTH.stat_month.desc()
).limit(1)
df = macro.run_query(q)
# 如果没有获取到数据,直接返回
if df.empty:
log.warn("未获取到CPI数据,跳过本次调仓")
return
# 获取CPI同比数据 (yoy: 上年同月=100)
# 注意:聚宽数据库中 yoy 字段通常是百分比数值,例如 103.5 代表上涨 3.5%
# 或者有些字段是直接的增长率,具体需看数据字典。
# 在 macro.MAC_CPI_MONTH 表中,'yoy' 字段通常表示"上年同月=100"。
# 因此,如果 yoy = 103.0,代表 CPI 同比增长 3.0%。
# 我们取 'yoy' 字段。
current_cpi_index = df['yoy'][0]
# 计算同比增长率 (例如 103.5 -> 3.5)
cpi_growth_rate = current_cpi_index - 100
# 打印日志方便调试
log.info(f"当前时间: {context.current_dt.date()}, 获取到的统计月份: {df['stat_month'][0]}, CPI指数(yoy): {current_cpi_index}, 同比增长: {cpi_growth_rate:.2f}%")
# 2. 交易逻辑判断
# 获取当前持仓市值
position_value = context.portfolio.positions[g.security].value
# 逻辑:如果 CPI 增长率 > 阈值 (3%),则清仓;否则满仓
if cpi_growth_rate > g.cpi_threshold:
# 判断是否持有仓位,如果有则卖出
if position_value > 0:
log.info(f"通胀过高 ({cpi_growth_rate:.2f}% > {g.cpi_threshold}%),执行清仓卖出。")
order_target(g.security, 0)
else:
# 判断是否空仓,如果是则买入
if position_value == 0:
log.info(f"通胀温和 ({cpi_growth_rate:.2f}% <= {g.cpi_threshold}%),执行满仓买入。")
# 用所有可用资金买入
order_value(g.security, context.portfolio.available_cash)
def after_code_changed(context):
"""
模拟交易更换代码后运行函数
"""
g.cpi_threshold = 3.0
代码关键点解析
- 数据获取 (
macro.run_query):- 我们使用了
macro.MAC_CPI_MONTH表。 - 未来函数规避:聚宽的
macro.run_query在回测中会自动处理数据的“发布日期”。例如,1月份的 CPI 通常在 2月中旬发布。在 2月1日回测时,系统只会返回 12月份的数据(因为1月份的还没发),从而避免了未来函数。
- 我们使用了
- 数据字段 (
yoy):- 在聚宽宏观数据库中,CPI 的
yoy字段通常表示“上年同月=100”。所以代码中使用了current_cpi_index - 100来计算实际的百分比增长率。
- 在聚宽宏观数据库中,CPI 的
- 交易频率 (
run_monthly):- 宏观数据变化较慢,按月调仓足以捕捉趋势,同时能减少交易手续费。
常见问题 (Q&A)
Q: 为什么回测时发现交易信号有延迟?
A: 这是正常的。宏观数据有发布滞后期。例如,2023年5月的 CPI 数据通常在 2023年6月9日-15日左右公布。在6月1日运行时,你只能看到4月的数据。策略必须基于“当时已知”的数据进行决策,这符合实盘逻辑。
Q: 可以结合其他指标吗?
A: 可以。单一的 CPI 指标可能过于粗糙。常见的改进方案是:
- CPI + PPI 剪刀差:同时获取 PPI 数据,分析利润空间。
- CPI + 技术指标:用 CPI 定大方向(多/空),用均线(如20日均线)定具体的买卖点。
- 利率债数据:结合国债收益率进行股债轮动。
Q: 如何查看更多宏观数据字段?
A: 在聚宽官网的“数据字典” -> “宏观经济数据”栏目中,可以找到所有可用的宏观表(如 GDP、PMI、货币供应量 M2 等)及其字段定义。
Q: 策略中的 ETF 可以换成股票吗?
A: 可以,但宏观择时通常针对大盘(Beta收益),个股受非系统性风险影响大,直接用宏观指标指导个股买卖效果可能不稳定。建议配合行业轮动或风格因子使用。