🚀 AI 一键生成 joinquant 策略代码

如何在 JoinQuant 平台用 Python 编写 MACD 金叉死叉交易策略?

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

问题描述

请帮我编写一个 MACD 指标金叉买入、死叉卖出的交易策略。

解决方案

这是一个基于 JoinQuant(聚宽)平台的 MACD 指标金叉买入、死叉卖出的单股票策略。

策略逻辑说明

  1. 指标定义:使用标准的 MACD 参数(快线12,慢线26,信号线9)。
  2. 金叉(买入信号):当 DIF 线(快线)上穿 DEA 线(慢线/信号线)时,视为金叉,全仓买入。
  3. 死叉(卖出信号):当 DIF 线(快线)下穿 DEA 线(慢线/信号线)时,视为死叉,清仓卖出。
  4. 数据获取:每日获取过去 100 天的收盘价数据以计算指标。
  5. 计算库:使用 talib 库进行高效的指标计算。

策略代码

# -*- coding: utf-8 -*-
# 导入函数库
from jqdata import *
import talib
import numpy as np

def initialize(context):
    """
    初始化函数,设定基准、股票池、费用等
    """
    # 设定沪深300作为基准
    set_benchmark('000300.XSHG')
    # 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    
    # 设定要操作的股票,这里以平安银行为例
    g.security = '000001.XSHE'
    
    # 设定MACD参数
    g.fast_period = 12
    g.slow_period = 26
    g.signal_period = 9
    
    # 设定交易费用(股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱)
    set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
    
    # 每日开盘时运行
    run_daily(market_open, time='every_bar')

def market_open(context):
    """
    每日交易逻辑
    """
    security = g.security
    
    # 获取过去100天的收盘价数据(保证有足够的数据计算MACD)
    # 注意:MACD计算需要一定长度的历史数据才能趋于稳定
    close_data = attribute_history(security, 100, '1d', ['close'])
    
    # 将数据转换为numpy数组,供talib使用
    close_array = close_data['close'].values
    
    # 使用talib计算MACD
    # macd_dif: 差离值 (快线)
    # macd_dea: 讯号线 (慢线)
    # macd_hist: 红绿柱
    macd_dif, macd_dea, macd_hist = talib.MACD(
        close_array, 
        fastperiod=g.fast_period, 
        slowperiod=g.slow_period, 
        signalperiod=g.signal_period
    )
    
    # 获取当前的DIF和DEA值(数组最后一个元素)
    current_dif = macd_dif[-1]
    current_dea = macd_dea[-1]
    
    # 获取上一时间点的DIF和DEA值(数组倒数第二个元素)
    prev_dif = macd_dif[-2]
    prev_dea = macd_dea[-2]
    
    # 检查是否有持仓
    current_position = context.portfolio.positions[security].closeable_amount
    # 获取当前可用现金
    cash = context.portfolio.available_cash
    
    # 交易逻辑判断
    
    # 金叉:上一时刻 DIF < DEA,且当前时刻 DIF > DEA
    if prev_dif < prev_dea and current_dif > current_dea:
        # 如果有现金,则全仓买入
        if cash > 0:
            order_value(security, cash)
            log.info("MACD金叉,买入 %s" % security)
            
    # 死叉:上一时刻 DIF > DEA,且当前时刻 DIF < DEA
    elif prev_dif > prev_dea and current_dif < current_dea:
        # 如果有持仓,则清仓卖出
        if current_position > 0:
            order_target(security, 0)
            log.info("MACD死叉,卖出 %s" % security)

代码关键点解析

  1. talib.MACD: 这是一个非常高效的技术分析库函数。它返回三个数组,分别是 DIF(快线)、DEA(慢线)和 MACD柱状图。
  2. attribute_history: 我们获取了过去 100 天的数据。虽然 MACD 参数是 12 和 26,但为了让 EMA(指数移动平均)的计算结果更加准确和收敛,通常需要比最长周期多 2-3 倍的数据量。
  3. 交叉判断逻辑:
    • 我们通过比较 [-1] (当前值) 和 [-2] (前一日值) 来判断交叉。
    • 如果昨天快线在慢线之下,今天快线在慢线之上,即为金叉
    • 如果昨天快线在慢线之上,今天快线在慢线之下,即为死叉
  4. order_valueorder_target:
    • order_value(security, cash): 用当前所有现金买入股票。
    • order_target(security, 0): 将股票仓位调整为 0,即清仓。

Q&A

Q: 为什么获取历史数据时要取 100 天,而不是 26 天?
A: MACD 的计算依赖于 EMA(指数移动平均),EMA 具有递归性质,初始值的设定会影响后续的计算结果。如果只取 26 天数据,计算出的 MACD 值在初期会非常不稳定且不准确。获取更多的数据(如 100 天或更多)可以让 EMA 充分收敛,使计算出的指标值与看盘软件上的数值一致。

Q: 如何将此策略修改为多只股票轮动?
A: 可以将 g.security 修改为一个股票列表(例如 g.stocks = ['000001.XSHE', '600519.XSHG']),然后在 market_open 函数中使用 for security in g.stocks: 循环遍历每一只股票,分别执行获取数据、计算指标和下单的逻辑。同时需要注意资金分配问题(例如每只股票分配总资金的 1/N)。

Q: 策略中的 set_option('use_real_price', True) 是什么作用?
A: 这行代码开启了动态复权模式(真实价格)。在回测中,股票会发生分红、拆股等事件,导致价格跳空。开启此选项后,聚宽会在回测引擎内部自动处理复权,使我们获取到的价格是连续的,避免因除权除息导致的技术指标计算错误(例如股价突然“腰斩”导致误触发死叉)。