🚀 AI 一键生成 joinquant 策略代码

如何在 JoinQuant 平台编写一个均值回归交易策略?

joinquant | 发布时间: 2025/11/26
以下内容由 EasyQuant 生成。

问题描述

请帮我写一个股票跌多了就买,涨多了就卖的反转策略。

解决方案

这是一个非常经典的**均值回归(Mean Reversion)**策略思路。在量化交易中,最常用的衡量“跌多了”或“涨多了”的技术指标是 RSI(相对强弱指标)

策略逻辑

  1. 核心思想:价格总是围绕价值上下波动,涨多了会回调,跌多了会反弹。
  2. 选股范围:沪深300成分股(流动性好,避免小盘股的流动性陷阱)。
  3. 买入条件:当股票的 RSI 指标低于 30 时,认为处于“超卖”状态(跌多了),执行买入。
  4. 卖出条件:当股票的 RSI 指标高于 70 时,认为处于“超买”状态(涨多了),执行卖出。
  5. 仓位管理:设定最大持仓股票数量(例如5只),每只股票等权重分配资金。

以下是基于聚宽(JoinQuant)API 实现的完整策略代码:

# -*- coding: utf-8 -*-
import jqdata
import talib
import numpy as np

def initialize(context):
    """
    初始化函数,设定基准、手续费、全局变量等
    """
    # 设定沪深300作为基准
    set_benchmark('000300.XSHG')
    # 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    # 过滤掉order系列API产生的比error级别低的log
    log.set_level('order', 'error')
    
    # 股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱
    set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
    
    # --- 策略参数设置 ---
    # RSI计算的时间周期,通常为14天
    g.rsi_period = 14
    # RSI买入阈值(跌多了)
    g.rsi_low = 30
    # RSI卖出阈值(涨多了)
    g.rsi_high = 70
    # 最大持仓股票数量
    g.max_holdings = 5
    
    # 每天开盘时运行
    run_daily(trade, 'every_bar')

def trade(context):
    """
    交易逻辑函数
    """
    # 1. 获取股票池:沪深300成分股
    # 也可以换成 get_all_securities(['stock']).index 获取全A股,但回测速度会变慢
    stock_pool = get_index_stocks('000300.XSHG')
    
    # 2. 卖出逻辑:遍历当前持仓
    for security in list(context.portfolio.positions.keys()):
        # 获取持仓对象
        position = context.portfolio.positions[security]
        # 如果可用仓位为0,跳过
        if position.closeable_amount == 0:
            continue
            
        # 获取计算RSI所需的历史收盘价数据
        # 取 rsi_period + 20 天的数据以确保 talib 计算结果稳定
        close_data = attribute_history(security, g.rsi_period + 20, '1d', ['close'])
        
        # 如果数据不足(比如停牌或新股),跳过
        if len(close_data) < g.rsi_period + 1:
            continue
            
        # 计算RSI
        close_prices = close_data['close'].values
        rsi_values = talib.RSI(close_prices, timeperiod=g.rsi_period)
        current_rsi = rsi_values[-1]
        
        # 如果 RSI > 70 (涨多了),卖出
        if current_rsi > g.rsi_high:
            order_target(security, 0)
            log.info("卖出 %s, RSI: %.2f (涨多了)" % (security, current_rsi))

    # 3. 买入逻辑
    # 如果持仓数量已达上限,则不再买入
    if len(context.portfolio.positions) >= g.max_holdings:
        return

    # 遍历股票池寻找买入机会
    for security in stock_pool:
        # 如果已经持仓,跳过
        if security in context.portfolio.positions:
            continue
        
        # 过滤停牌和ST股票(可选,这里简单处理,attribute_history会自动处理停牌数据填充)
        # 获取历史数据
        close_data = attribute_history(security, g.rsi_period + 20, '1d', ['close'])
        
        if len(close_data) < g.rsi_period + 1:
            continue
            
        # 计算RSI
        close_prices = close_data['close'].values
        # 处理可能存在的NaN值
        if np.isnan(close_prices).any():
            continue
            
        rsi_values = talib.RSI(close_prices, timeperiod=g.rsi_period)
        current_rsi = rsi_values[-1]
        
        # 如果 RSI < 30 (跌多了),且持仓未满,买入
        if current_rsi < g.rsi_low:
            # 计算每只股票应该分配的资金:总资产 / 最大持仓数
            # 注意:这里简单均分,实际资金可能因为卖出操作而变化
            target_value = context.portfolio.total_value / g.max_holdings
            
            # 检查可用资金是否足够
            if context.portfolio.available_cash > target_value * 0.9: # 0.9是为了留点余地给手续费
                order_target_value(security, target_value)
                log.info("买入 %s, RSI: %.2f (跌多了)" % (security, current_rsi))
                
                # 如果买入后达到持仓上限,停止循环
                if len(context.portfolio.positions) >= g.max_holdings:
                    break

代码关键点解析

  1. talib.RSI: 使用了 talib 库来计算 RSI 指标。这是金融领域标准的计算库,比自己写公式更准确、效率更高。
  2. attribute_history: 获取过去一段时间的收盘价。为了计算 14 日 RSI,我们需要获取比 14 天更多的数据(代码中取了 g.rsi_period + 20),因为指标计算通常需要一定的预热数据来消除初始值的偏差。
  3. 仓位控制:
    • g.max_holdings = 5: 限制最多持有5只股票,防止资金过于分散或满仓单一股票风险过大。
    • order_target_value: 按照目标价值下单,系统会自动计算需要买入多少股(自动向下取整到100股的倍数)。
  4. 买卖顺序: 先执行卖出逻辑释放资金,再执行买入逻辑,这样可以提高资金利用率。

常见问题 (Q&A)

Q: 为什么选择 RSI 指标?
A: RSI(相对强弱指标)是衡量价格变动速度和幅度的经典动量指标。它在 0 到 100 之间波动,直观地反映了市场的超买(>70)和超卖(<30)状态,非常适合定义“涨多了”和“跌多了”。

Q: 这个策略适合什么市场环境?
A: 反转策略最适合震荡市。在单边的大牛市中,RSI可能长期高于70(导致过早卖出);在单边大熊市中,RSI可能长期低于30(导致过早抄底被套,即“接飞刀”)。

Q: 如何改进这个策略?
A:

  1. 增加止损:反转策略容易“抄在半山腰”,可以加入固定比例止损(如亏损10%强平)。
  2. 结合基本面:只在基本面良好(如PE较低、盈利增长)的股票池中做反转,避免买入即将退市的垃圾股。
  3. 动态阈值:在牛市中将买入阈值提高(如40),在熊市中将卖出阈值降低(如60)。

Q: 为什么回测时没有交易?
A: 可能是因为选定的时间段内,沪深300成分股波动较小,没有触发 RSI < 30 或 RSI > 70 的极端情况。你可以尝试调整阈值(例如改为 40/60)或者扩大股票池(例如使用中证500)。