🚀 AI 一键生成 joinquant 策略代码

JoinQuant KDJ 指标金叉死叉策略的 Python 代码实现

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

问题描述

我想写一个 KDJ 指标的交易策略,当 K 线上穿 D 线时买入,下穿时卖出。

解决方案

这是一个基于 KDJ 指标的经典趋势跟踪策略。

策略逻辑

  1. 指标计算:使用 KDJ 指标(随机指标),通常参数设置为 N=9, M1=3, M2=3。
  2. 买入信号(金叉):当 K 线由下向上穿过 D 线时(即上一期 K < D,且当前 K > D),全仓买入。
  3. 卖出信号(死叉):当 K 线由上向下穿过 D 线时(即上一期 K > D,且当前 K < D),清仓卖出。

策略代码

以下是基于聚宽(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)
    
    # 设置交易费用:买入万分之三,卖出万分之三加千分之一印花税,最低5元
    set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
    
    # 设定要操作的股票,这里以平安银行为例
    g.security = '000001.XSHE'
    
    # KDJ 指标参数 (N, M1, M2)
    g.N = 9
    g.M1 = 3
    g.M2 = 3
    
    # 每天开盘时运行策略
    run_daily(market_open, time='09:30')

def market_open(context):
    """
    每日交易逻辑
    """
    security = g.security
    
    # 获取历史数据
    # KDJ计算需要High, Low, Close数据
    # 获取过去 50 天的数据以确保计算指标时有足够的预热数据
    data = attribute_history(security, 50, '1d', ['high', 'low', 'close'], df=False)
    
    # 提取数据为 numpy 数组,talib 需要 numpy 格式
    high_prices = data['high']
    low_prices = data['low']
    close_prices = data['close']
    
    # 检查数据长度是否足够
    if len(close_prices) < 20:
        return

    # 使用 talib 计算 KDJ
    # STOCH 函数返回 K 和 D 的值
    # fastk_period 对应 N
    # slowk_period 对应 M1
    # slowd_period 对应 M2
    K, D = talib.STOCH(high_prices, 
                       low_prices, 
                       close_prices, 
                       fastk_period=g.N, 
                       slowk_period=g.M1, 
                       slowk_matype=0, 
                       slowd_period=g.M2, 
                       slowd_matype=0)
    
    # 获取当前和上一期的 K、D 值
    # [-1] 为当前值,[-2] 为上一期值
    current_k = K[-1]
    current_d = D[-1]
    prev_k = K[-2]
    prev_d = D[-2]
    
    # 获取当前账户资金和持仓
    curr_position = context.portfolio.positions[security].total_amount
    available_cash = context.portfolio.available_cash
    
    # 交易信号判断
    
    # 金叉:K线上穿D线 (上期 K < D 且 本期 K > D)
    golden_cross = (prev_k < prev_d) and (current_k > current_d)
    
    # 死叉:K线下穿D线 (上期 K > D 且 本期 K < D)
    death_cross = (prev_k > prev_d) and (current_k < current_d)
    
    # 执行交易
    if golden_cross and available_cash > 0:
        # 买入所有可用资金
        order_value(security, available_cash)
        log.info("KDJ金叉,买入 %s,当前K: %.2f, 当前D: %.2f" % (security, current_k, current_d))
        
    elif death_cross and curr_position > 0:
        # 卖出所有持仓
        order_target(security, 0)
        log.info("KDJ死叉,卖出 %s,当前K: %.2f, 当前D: %.2f" % (security, current_k, current_d))

    # 记录KDJ值以便在回测图表中查看
    record(K=current_k, D=current_d)

代码解析

  1. 数据获取 (attribute_history):

    • KDJ 计算依赖于最高价(High)、最低价(Low)和收盘价(Close)。
    • 我们获取了过去 50 天的数据。虽然 KDJ 参数通常是 9 天,但指标计算(特别是平滑处理)需要一定长度的历史数据来消除初始值的偏差,因此取 50 天比较稳妥。
  2. 指标计算 (talib.STOCH):

    • 使用了 Python 的金融技术分析库 talib。这是计算指标最高效、最标准的方法。
    • talib.STOCH 直接返回 K 线和 D 线的数据序列。
    • 参数对应关系:fastk_period 对应 KDJ 中的 N(周期),slowk_period 对应 M1,slowd_period 对应 M2。
  3. 信号判断:

    • 金叉:判断逻辑为 prev_k < prev_d (昨天 K 在 D 下方) 且 current_k > current_d (今天 K 在 D 上方)。
    • 死叉:判断逻辑为 prev_k > prev_d (昨天 K 在 D 上方) 且 current_k < current_d (今天 K 在 D 下方)。
  4. 交易执行:

    • 使用 order_value 进行买入,使用 order_target 进行卖出(设为 0 即清仓)。

常见问题 (Q&A)

Q: 为什么使用 talib 而不是自己写公式计算 KDJ?
A: talib 是经过高度优化的 C 语言底层库,计算速度极快且结果标准。自己编写公式容易在平滑算法(如 SMA, EMA 的选择)上出现偏差,导致与主流软件结果不一致。

Q: 如何修改 KDJ 的参数,例如改为 (18, 6, 6)?
A: 在 initialize 函数中修改 g.N, g.M1, g.M2 的值即可。例如:g.N = 18, g.M1 = 6, g.M2 = 6

Q: 这个策略可以用于多只股票吗?
A: 当前代码仅针对单只股票(g.security)。如果要操作多只股票,需要将 g.security 改为一个列表,并在 market_open 函数中使用 for 循环遍历列表,对每一只股票分别计算指标和下单。

Q: 为什么有时候会出现 KDJ 钝化(长期在高位或低位)导致信号失效?
A: KDJ 是一个敏感的摆动指标,在单边强趋势行情中容易出现钝化(即一直提示超买或超卖但价格继续上涨或下跌)。在实盘中,通常建议结合均线(MA)或 MACD 等趋势指标进行过滤,避免在强趋势中逆势操作。