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

JoinQuant 聚宽量化平台:如何编写首次金叉买入策略(附Python源码)

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

问题描述

如何设置在首次出现金叉时买入?

设置一个策略,每天循环,金叉时买入。比如金叉第一天时买入了,但第二第三天第四天还处于金叉阶段并符合买入条件,怎么设置只在首次出现金叉时买入,其余时间不买入呢?

解决方案

在量化交易中,“金叉”通常指的是短期均线上穿长期均线。要实现**“只在首次出现金叉时买入,而在金叉持续期间不重复买入”,核心在于将“金叉”从一个持续的状态转化为一个瞬间的事件**。

核心逻辑

要判断“首次金叉”,我们需要同时对比昨天今天的均线状态:

  1. 昨天:短期均线 $\le$ 长期均线(还没金叉,或者刚好粘合)
  2. 今天:短期均线 $>$ 长期均线(已经金叉)

只有同时满足这两个条件,才说明今天是“首次”发生金叉。如果昨天短均线已经大于长均线,今天依然大于,说明处于金叉的延续阶段,不触发买入。

此外,为了更加严谨,我们还可以结合账户持仓状态进行双重过滤:如果当前已经持有该股票,则不再买入。

JoinQuant 策略源码示例

以下是一个完整的 JoinQuant 策略代码,以 5日均线(MA5)上穿 10日均线(MA10)为例:

# 导入聚宽函数库
import jqdata

# 初始化函数
def initialize(context):
    # 设定要操作的股票:平安银行
    g.security = '000001.XSHE'
    # 设定沪深300作为基准
    set_benchmark('000300.XSHG')
    # 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    
    # 每天开盘时运行
    run_daily(market_open, time='09:30')

def market_open(context):
    security = g.security
    
    # 为了计算今天和昨天的 MA10,我们至少需要过去 11 天的收盘价数据
    # 获取过去 11 天的收盘价
    close_data = attribute_history(security, 11, '1d', ['close'])
    if len(close_data) < 11:
        return # 数据不足,跳过
        
    close_prices = close_data['close']
    
    # 计算今天的 MA5 和 MA10 (包含昨天及之前的4天/9天,加上今天开盘前能获取到的最新价,即昨收)
    # 注意:在每天 09:30 运行 attribute_history 获取的日线数据,最后一条是昨天的收盘价
    # 所以这里的“今天”实际上是基于昨天收盘后的数据计算的均线,用于今天开盘的决策
    ma5_today = close_prices[-5:].mean()
    ma10_today = close_prices[-10:].mean()
    
    # 计算昨天的 MA5 和 MA10 (排除最后一天的数据)
    ma5_yesterday = close_prices[-6:-1].mean()
    ma10_yesterday = close_prices[-11:-1].mean()
    
    # 获取当前资金和持仓
    cash = context.portfolio.available_cash
    current_position = context.portfolio.positions[security].closeable_amount
    
    # 核心判断:首次金叉事件
    # 条件1:昨天 MA5 <= MA10
    # 条件2:今天 MA5 > MA10
    is_first_golden_cross = (ma5_yesterday <= ma10_yesterday) and (ma5_today > ma10_today)
    
    # 判断死叉事件(用于卖出)
    is_dead_cross = (ma5_yesterday >= ma10_yesterday) and (ma5_today < ma10_today)

    # 如果是首次金叉,并且当前没有持仓,并且有可用资金
    if is_first_golden_cross and current_position == 0 and cash > 0:
        # 全仓买入
        order_value(security, cash)
        log.info("触发首次金叉!买入 %s" % security)
        
    # 如果出现死叉,并且当前有持仓
    elif is_dead_cross and current_position > 0:
        # 清仓卖出
        order_target(security, 0)
        log.info("触发死叉!卖出 %s" % security)

代码解析与进阶技巧

  1. 数据切片计算均线
    代码中使用了 close_prices[-5:].mean() 来计算当期均线,使用 close_prices[-6:-1].mean() 来计算上一期均线。这种切片方法非常高效,避免了调用复杂的指标库。
  2. 持仓状态过滤 (current_position == 0)
    即使你的策略逻辑在某些极端情况下(例如数据微小波动导致连续两天触发金叉条件),加上 current_position == 0 的判断可以作为最后一道防线,确保只要手里有票,就不会重复执行买入指令。
  3. 日线数据的时效性
    run_daily(..., time='09:30') 中调用 attribute_history(..., '1d'),获取到的最后一条数据是昨天的日线。因此,策略实际上是在每天开盘时,根据昨天收盘后形成的均线形态来决定今天的交易。