找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1186

积分

0

好友

210

主题
发表于 3 天前 | 查看: 5| 回复: 0

本文将详细解析如何在迅投QMT量化平台使用Python实现一个基于KDJ随机指标的交易策略,涵盖指标的核心计算逻辑、超买超卖信号判断以及自动下单执行流程,并提供可直接运行的回测与实盘代码。

策略核心逻辑

本策略的核心思想是利用KDJ指标中的J值识别市场的超买与超卖状态,以此作为买卖依据。其具体逻辑如下:

  1. 指标计算:以经典参数(N=9, M1=3, M2=3)计算KDJ值。
    • RSV = (收盘价 - N日内最低价) / (N日内最高价 - N日内最低价) × 100
    • K = 2/3 × 前一日K值 + 1/3 × 当日RSV
    • D = 2/3 × 前一日D值 + 1/3 × 当日K值
    • J = 3 × K - 2 × D
  2. 买入信号:当J值低于20时,判定市场处于超卖状态,策略将执行满仓买入
  3. 卖出信号:当J值高于80时,判定市场处于超买状态,策略将执行清仓卖出

完整的策略代码实现

以下是为QMT平台编写的完整Python策略代码,你可以直接复制到策略编辑器中使用。

# -*- coding: gbk -*-
import pandas as pd
import numpy as np

def init(ContextInfo):
    """
    初始化函数,策略启动时调用一次
    """
    # 设置资金账号,请修改为您的实际账号
    # 格式如:'6000000248'
    ContextInfo.account_id = 'YOUR_ACCOUNT_ID' 
    ContextInfo.set_account(ContextInfo.account_id)

    # 策略参数设置
    ContextInfo.N = 9      # 计算RSV的周期
    ContextInfo.M1 = 3     # K值的平滑周期
    ContextInfo.M2 = 3     # D值的平滑周期

    # 设置交易标的,这里默认为当前主图显示的品种
    # 如果需要固定品种,可以设置为 ContextInfo.stock_code = '600000.SH'
    ContextInfo.stock_code = ContextInfo.stockcode + '.' + ContextInfo.market

    print("策略初始化完成,交易标的:", ContextInfo.stock_code)

def get_kdj(df, N, M1, M2):
    """
    计算KDJ指标的辅助函数
    """
    # 计算 RSV
    low_list = df['low'].rolling(window=N).min()
    high_list = df['high'].rolling(window=N).max()
    rsv = (df['close'] - low_list) / (high_list - low_list) * 100

    # 填充NaN值,防止计算中断
    rsv = rsv.fillna(50)

    # 计算 K, D, J
    # 注意:国内主流软件(如通达信、同花顺)的KDJ算法中,平滑因子通常为 1/M
    # pandas的ewm中,alpha = 1/com + 1,这里使用 com = M-1 来近似 SMA 迭代逻辑
    # K = (M1-1)/M1 * PrevK + 1/M1 * RSV  => alpha = 1/M1
    k = rsv.ewm(alpha=1/M1, adjust=False).mean()
    d = k.ewm(alpha=1/M2, adjust=False).mean()
    j = 3 * k - 2 * d

    return k, d, j

def handlebar(ContextInfo):
    """
    K线周期回调函数
    """
    # 获取当前正在处理的K线索引
    index = ContextInfo.barpos

    # 获取历史行情数据,多取一些数据以保证指标计算准确
    # 获取 Open, High, Low, Close
    data_len = 100 
    df_dict = ContextInfo.get_market_data_ex(
        ['open', 'high', 'low', 'close'], 
        [ContextInfo.stock_code], 
        period=ContextInfo.period, 
        count=data_len,
        dividend_type='follow' # 跟随主图复权
    )

    if ContextInfo.stock_code not in df_dict:
        return

    df = df_dict[ContextInfo.stock_code]

    # 数据长度不足以计算指标时直接返回
    if len(df) < ContextInfo.N + 2:
        return

    # 计算 KDJ
    k, d, j = get_kdj(df, ContextInfo.N, ContextInfo.M1, ContextInfo.M2)

    # 获取当前K线的 J 值
    # 注意:在回测中,iloc[-1]是当前bar;在实盘中,iloc[-1]是最新的一根K线(可能未走完)
    current_j = j.iloc[-1]
    current_k = k.iloc[-1]
    current_d = d.iloc[-1]

    # 获取当前价格
    current_price = df['close'].iloc[-1]

    # 打印日志方便调试
    # print(f"时间: {df.index[-1]}, K: {current_k:.2f}, D: {current_d:.2f}, J: {current_j:.2f}")

    # --- 交易逻辑 ---

    # 1. 买入信号:J < 20
    if current_j < 20:
        # 使用 order_target_percent 调整仓位到 100% (满仓买入)
        # 如果已经是满仓,该函数不会重复下单
        order_target_percent(ContextInfo.stock_code, 1.0, ContextInfo, ContextInfo.account_id)
        # 只有在最后一根K线(实盘最新时刻)才打印信号,避免回测刷屏
        if ContextInfo.is_last_bar():
            print(f"触发买入信号 (J={current_j:.2f} < 20),执行买入。")

    # 2. 卖出信号:J > 80
    elif current_j > 80:
        # 使用 order_target_percent 调整仓位到 0% (清仓卖出)
        order_target_percent(ContextInfo.stock_code, 0.0, ContextInfo, ContextInfo.account_id)
        if ContextInfo.is_last_bar():
            print(f"触发卖出信号 (J={current_j:.2f} > 80),执行卖出。")

下图形象地展示了KDJ指标与股价的互动关系,有助于理解超买超卖区域:

像素化图像

关键代码解析与使用说明

  1. 编码与账号设置

    • 首行# -*- coding: gbk -*-是必须的,用于兼容QMT Python编辑器的GBK编码环境,避免中文乱码。
    • 重要:务必在init函数中将YOUR_ACCOUNT_ID替换为你自己的真实资金账号(字符串格式)。
  2. 数据与指标计算

    • 代码中使用了QMT高效的get_market_data_ex接口获取行情数据。
    • 利用Pandas库手动实现了KDJ算法。为了与国内主流交易软件(如通达信)的SMA(简单移动平均)迭代算法保持一致,这里使用ewm(指数加权移动平均)并设置alpha=1/3进行近似,确保计算出的K、D、J值具有可比性。如果你想深入学习数据分析技巧,可以探索我们社区整理的Python相关资料。
  3. 交易执行与仓位管理

    • 策略使用order_target_percent函数进行交易,这是一种基于目标持仓比例的智能下单方式。
      • J < 20时,设置目标持仓比例为1.0(即100%),系统会自动买入至满仓。
      • J > 80时,设置目标持仓比例为0.0,系统会自动清仓所有持仓。
    • 这种方法能有效避免在同一信号点上重复下单,简化了仓位管理逻辑。这本质上是一种基于特定市场状态(超买超卖)的固定算法规则。
  4. 运行模式

    • 回测:在QMT策略编辑器中点击“回测”按钮,设置好回测时间区间和基准对比即可进行历史业绩验证。
    • 实盘:在策略编辑器中点击“运行”,或在“模型交易”界面加载此策略。在实盘模式下,handlebar函数会随着行情Tick更新而触发,交易信号基于最新的K线数据生成。

常见问题与优化方向

Q:计算出的J值与行情软件显示有细微差异?
A:这通常是由于KDJ指标初始值(首根K线的K、D值)的设定方式不同导致的。随着计算数据的积累,这种差异会迅速收敛至可忽略的程度。代码中已对平滑算法进行了对齐处理。

Q:如何避免盘中信号闪烁,只在K线收盘时下单?
A:QMT实盘时,最后一根未完结的K线会随每个Tick触发handlebar。若希望基于已收盘的K线交易,可在代码中判断ContextInfo.is_new_bar(),若为新K线开始,则取上一根已收盘K线(iloc[-2])的J值作为交易信号依据。

Q:如何将此策略应用于多只股票?
A:可在init函数中使用ContextInfo.set_universe(['600000.SH', '000001.SZ'])设置股票池。随后在handlebar中遍历ContextInfo.get_universe()返回的列表,为每只股票分别获取数据、计算指标并执行独立的交易逻辑。




上一篇:C语言动态内存管理:malloc、free与realloc实战指南与内存泄漏防护
下一篇:SpringBoot与Vue开发果蔬作物病虫害识别防治系统(11300)设计与实现
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-17 21:38 , Processed in 0.107776 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表