3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在量化交易中,单一策略很难适应所有的市场环境。通过构建双模式切换策略,在市场强势期(多头市场)聚焦高弹性的科技股,在弱势期(空头/震荡市场)切换至避险或具有低相关性的全球ETF动量组合,是实现资产稳健增值的有效手段。
以下是在聚宽(JoinQuant)平台实现该策略的核心逻辑与完整代码。
市场强弱判别器(Market Regime Filter):
科技股策略(强势期):
全球ETF动量策略(弱势期):
模式切换与清仓逻辑(Switch & Liquidation):
请在聚宽回测环境中运行以下代码(建议回测频率:分钟或天,开启真实价格模式):
import pandas as pd
import numpy as np
from jqdata import *
def initialize(context):
# 1. 基础设置
set_benchmark('000300.XSHG')
set_option('use_real_price', True) # 开启真实价格模式
# 2. 交易税费设置
set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
# 3. 策略参数定义
g.filter_indexes = ['000300.XSHG', '399006.XSHE'] # 强弱判别指数:沪深300,创业板指
g.ma_window = 20 # 均线周期
# 科技股池(计算机与互联网行业)
g.tech_industry = ['I64', 'I65']
# 全球/避险 ETF 池
g.etf_pool = [
'511880.XSHG', # 黄金ETF
'513100.XSHG', # 纳指ETF
'513500.XSHG', # 标普500ETF
'511010.XSHG' # 国债ETF
]
# 记录当前运行模式:'INIT' (初始), 'TECH' (科技股), 'ETF' (动量ETF)
g.current_mode = 'INIT'
# 定时运行:每天9:30运行
run_daily(market_open, time='9:30')
def market_open(context):
# 1. 判断市场强弱
is_strong = check_market_strength(context)
target_mode = 'TECH' if is_strong else 'ETF'
log.info(f"当前市场判定: {'强势' if is_strong else '弱势'} | 目标模式: {target_mode} | 当前持仓模式: {g.current_mode}")
# 2. 模式切换清仓逻辑
if g.current_mode != target_mode:
log.info(f"检测到模式切换!从 {g.current_mode} 切换至 {target_mode}。执行全仓清空...")
for stock in list(context.portfolio.positions.keys()):
order_target(stock, 0)
g.current_mode = target_mode
# 清仓后直接返回,等待下一分钟或下一交易日再建仓,确保资金完全释放
return
# 3. 执行对应模式的建仓/调仓
cash = context.portfolio.available_cash
if cash < 10000: # 资金不足则不调仓
return
if g.current_mode == 'TECH':
# 强势期:买入龙头科技股
tech_stocks = get_tech_leaders(context)
if tech_stocks:
log.info(f"强势期建仓科技股: {tech_stocks}")
target_value = context.portfolio.total_value / len(tech_stocks)
# 卖出不在目标池的股票
for stock in list(context.portfolio.positions.keys()):
if stock not in tech_stocks:
order_target(stock, 0)
# 买入目标股票
for stock in tech_stocks:
order_target_value(stock, target_value)
elif g.current_mode == 'ETF':
# 弱势期:全球ETF动量轮动
target_etfs = get_etf_momentum(context)
if target_etfs:
log.info(f"弱势期建仓动量ETF: {target_etfs}")
target_value = context.portfolio.total_value / len(target_etfs)
# 卖出不在目标池的ETF
for stock in list(context.portfolio.positions.keys()):
if stock not in target_etfs:
order_target(stock, 0)
# 买入目标ETF
for stock in target_etfs:
order_target_value(stock, target_value)
def check_market_strength(context):
"""根据多指数均线判断市场强弱"""
for index in g.filter_indexes:
# 获取历史收盘价
close_data = attribute_history(index, g.ma_window + 1, '1d', ['close'])
ma = close_data['close'][:-1].mean() # 不包含当天的MA
current_price = close_data['close'][-1]
# 只要有一个指数低于均线,即判定为弱势
if current_price < ma:
return False
return True
def get_tech_leaders(context):
"""获取市值前5的龙头科技股"""
stocks = []
for ind in g.tech_industry:
stocks.extend(get_industry_stocks(ind, date=context.current_dt))
# 查询市值
q = query(valuation.code, valuation.market_cap).filter(
valuation.code.in_(stocks)
).order_by(valuation.market_cap.desc()).limit(5)
df = get_fundamentals(q, date=context.previous_date)
return list(df['code'])
def get_etf_momentum(context):
"""计算ETF过去20天涨幅,返回前2名"""
momentum_dict = {}
for etf in g.etf_pool:
close_data = attribute_history(etf, 21, '1d', ['close'])
if len(close_data) >= 21:
return_20d = (close_data['close'][-1] - close_data['close'][0]) / close_data['close'][0]
momentum_dict[etf] = return_20d
# 按涨幅降序排序,取前2名
sorted_etfs = sorted(momentum_dict.items(), key=lambda x: x[1], reverse=True)
return [sorted_etfs[0][0], sorted_etfs[1][0]]
check_market_strength 中,计算均线时使用了 close_data['close'][:-1].mean(),排除了当天未收盘的价格,确保回测的真实性。g.current_mode != target_mode 时,策略会执行 order_target(stock, 0) 清仓,并执行 return 结束当天的操作。这样可以防止在同一天内由于清仓资金未及时到账而导致建仓失败,在下一个交易日资金充足时再行建仓,更加符合实盘逻辑。