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

1186

积分

0

好友

210

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

策略逻辑概述

本教程旨在详解如何在 QMT 量化交易平台上,使用 Python 编写一个经典的 MACD 指标交易策略。该策略遵循以下核心逻辑:

  1. 指标计算:通过 talib 库计算 MACD 指标,包括快线 (DIF)、慢线 (DEA) 和柱状图 (MACD)。默认参数为 12, 26, 9。
  2. 交易信号
    • 金叉 (买入信号):当 DIF 线由下向上穿过 DEA 线时触发。
    • 死叉 (卖出信号):当 DIF 线由上向下穿过 DEA 线时触发。
  3. 执行规则
    • 出现金叉信号且账户无该股票持仓时,执行买入操作。
    • 出现死叉信号且账户持有该股票时,执行卖出清仓操作。

完整的 Python 策略源码

以下代码可直接复制到 QMT 策略编辑器中使用。通过编写此类策略,你可以深入理解 Python 在金融数据分析与自动化交易中的应用。

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

def init(ContextInfo):
    """
    初始化函数,策略启动时调用一次
    """
    # 设置资金账号 (请修改为您自己的资金账号)
    ContextInfo.accid = '6000000000' 
    # 设置账号类型:'STOCK'股票, 'FUTURE'期货
    ContextInfo.accountType = 'STOCK'

    # 绑定账号,用于接收回报
    ContextInfo.set_account(ContextInfo.accid)

    # 设置MACD参数
    ContextInfo.fast_period = 12
    ContextInfo.slow_period = 26
    ContextInfo.signal_period = 9

    print("策略初始化完成,MACD参数: {}, {}, {}".format(
        ContextInfo.fast_period, ContextInfo.slow_period, ContextInfo.signal_period))

def handlebar(ContextInfo):
    """
    K线处理函数,每根K线执行一次
    """
    # 获取当前主图的股票代码
    stock_code = ContextInfo.stockcode
    # 获取当前主图的周期
    period = ContextInfo.period

    # 1. 获取历史行情数据
    # 获取足够多的数据以确保MACD计算准确,这里取过去100根K线
    data_len = 100
    # 使用 get_market_data_ex 获取数据 (推荐方式)
    # dividend_type='front' 表示前复权,计算技术指标通常使用前复权
    market_data = ContextInfo.get_market_data_ex(
        ['close'], 
        [stock_code], 
        period=period, 
        count=data_len, 
        dividend_type='front'
    )

    # 如果数据获取失败或数据量不足,直接返回
    if stock_code not in market_data or len(market_data[stock_code]) < 35:
        return

    # 提取收盘价序列
    close_price = market_data[stock_code]['close']
    # 转为numpy数组,方便talib计算
    close_np = np.array(close_price)

    # 2. 计算 MACD 指标
    # diff: 快线, dea: 慢线, macd: 柱状图
    diff, dea, macd = talib.MACD(
        close_np, 
        fastperiod=ContextInfo.fast_period, 
        slowperiod=ContextInfo.slow_period, 
        signalperiod=ContextInfo.signal_period
    )

    # 获取当前K线和上一根K线的指标值
    # -1 代表当前最新一根K线(如果是盘中,则是正在跳动的K线)
    # -2 代表上一根K线
    current_diff = diff[-1]
    current_dea = dea[-1]
    last_diff = diff[-2]
    last_dea = dea[-2]

    # 检查是否计算出有效值 (剔除NaN)
    if np.isnan(current_diff) or np.isnan(last_diff):
        return

    # 3. 判断金叉和死叉
    # 金叉:上一根K线 DIF < DEA,且当前K线 DIF > DEA
    golden_cross = (last_diff < last_dea) and (current_diff > current_dea)

    # 死叉:上一根K线 DIF > DEA,且当前K线 DIF < DEA
    death_cross = (last_diff > last_dea) and (current_diff < current_dea)

    # 4. 获取当前持仓情况
    # 注意:回测模式下,ContextInfo.get_position() 可能不可用,需用 get_trade_detail_data
    # 这里为了兼容实盘和回测,简单判断持仓
    positions = ContextInfo.get_trade_detail_data(ContextInfo.accid, ContextInfo.accountType, 'POSITION')
    current_vol = 0
    for pos in positions:
        if pos.m_strInstrumentID == stock_code:
            current_vol = pos.m_nVolume
            break

    # 5. 交易逻辑执行
    # 获取最新价格用于下单
    last_price = close_price.iloc[-1]

    # 只有在K线走完时才下单(避免盘中信号闪烁),或者使用 ContextInfo.is_last_bar() 判断
    # 这里演示简单逻辑:如果是回测,每根bar都会执行;如果是实盘,通常在bar结束或tick级判断

    # --- 买入逻辑 ---
    if golden_cross:
        if current_vol == 0:
            # 记录日志
            print(f"[{ContextInfo.barpos}] {stock_code} 触发金叉,买入")
            # 绘制信号到图表
            ContextInfo.draw_text(True, last_price, '金叉买入')

            # 下单:全仓买入 (这里简单演示买入1000股,实际需根据资金计算)
            # opType=23(买入), orderType=1101(单股单账号普通下单), priceType=5(最新价)
            passorder(23, 1101, ContextInfo.accid, stock_code, 5, -1, 1000, ContextInfo)

    # --- 卖出逻辑 ---
    elif death_cross:
        if current_vol > 0:
            # 记录日志
            print(f"[{ContextInfo.barpos}] {stock_code} 触发死叉,卖出")
            # 绘制信号到图表
            ContextInfo.draw_text(True, last_price, '死叉卖出')

            # 下单:卖出所有持仓
            # opType=24(卖出)
            passorder(24, 1101, ContextInfo.accid, stock_code, 5, -1, current_vol, ContextInfo)

    # 6. 在副图画出MACD指标 (可选,方便回测观察)
    ContextInfo.paint('DIFF', current_diff, -1, 0, 'white')
    ContextInfo.paint('DEA', current_dea, -1, 0, 'yellow')
    # 画柱状图
    macd_color = 'red' if macd[-1] > 0 else 'green'
    ContextInfo.paint('MACD', macd[-1] * 2, -1, 42, macd_color) # talib算出的macd通常是diff-dea,国内软件习惯显示(diff-dea)*2

策略部署与运行步骤

  1. 新建策略:在 QMT 客户端内打开策略编辑器,创建一个新的 Python 策略文件。
  2. 粘贴代码:将上述完整代码复制到新建的策略文件中。
  3. 配置账号:找到 init 函数里的 ContextInfo.accid = '6000000000',将其中的账号字符串替换成你自己的真实资金账号。
  4. 补充历史数据
    • 点击 QMT 菜单栏的【数据管理】->【补充数据】。
    • 选择需要回测或交易的股票,下载相应的日线或分钟线历史数据。
  5. 执行策略
    • 回测:在编辑器点击“回测”按钮,设置好时间范围、基准和交易费率后即可开始。
    • 实盘/模拟:在行情K线图上加载该策略,或通过“模型交易”界面进行运行。

核心代码解析

数据获取与处理

  • get_market_data_ex:这是 QMT 推荐的行情获取接口。参数 dividend_type='front' 指使用前复权数据,这对计算 MACD 等基于价格的技术指标至关重要,可以避免因除权除息导致的指标跳空失真。
  • 数据清洗:代码中检查了数据是否存在及长度是否足够(大于35根,以确保MACD能计算出有效值),这是构建健壮策略的基础。

指标计算

  • talib.MACD:QMT 内置了强大的 talib 技术分析库。需要注意的是,talib 返回的 macd 序列值通常是 (DIF - DEA),而国内主流软件(如通达信)显示的 MACD 柱状图是 (DIF - DEA) * 2。因此,在最后的绘图部分对数值进行了 * 2 处理以符合观察习惯。

交易下单

  • passorder:这是 QMT 最核心的下单函数。
    • 23 代表买入操作,24 代表卖出操作。
    • 1101 表示单市场、单股票、按数量下单的模式。
    • 5 表示以最新价 (PriceType.LATEST) 下单。在回测中,此价格通常对应K线的收盘价;在实盘中,则对应触发时的最新Tick价格。

常见问题与优化建议

Q: 回测时没有产生任何交易怎么办?

A: 首先,请确认已正确下载了标的股票的历史数据。其次,检查代码中 ContextInfo.accid 是否已修改或设置为有效的回测账号(部分回测上下文可能需要特定ID)。最后,检查MACD参数是否过于敏感或迟钝,导致在回测区间内未产生金叉/死叉信号。

Q: 如何调整 MACD 的计算参数?

A: 直接修改 init 函数中的 ContextInfo.fast_period, ContextInfo.slow_period, ContextInfo.signal_period 这三个变量的值即可。

Q: 实盘中如何防止因K线未走完导致的信号闪烁?

A: 当前代码在 handlebar 函数中运行,在实盘Tick级推送下可能每笔成交都会触发计算。为了避免在单根K线内因价格波动反复开平仓,可以加入时间过滤逻辑。例如,使用 ContextInfo.is_last_bar() 判断是否为K线最后一笔,或限定仅在交易日特定时间(如下午14:55之后)才允许发出交易指令。

策略逻辑示意图(如金叉死叉识别点)可帮助理解买卖时机,如下图所示:

Python实现QMT平台MACD量化交易策略:金叉买入与死叉卖出源码详解 - 图片 - 1


提示:本策略为MACD基础应用示例,实际交易中需结合风险管理、仓位控制等多方面因素进行完善。对利用人工智能方法生成或优化量化策略模型感兴趣的读者,可以关注相关领域的最新进展。




上一篇:PostCSS现代CSS开发指南:核心概念、常用插件与配置实践
下一篇:从原理到实战:数字图像处理核心技术与最新应用(含深度学习、CNN)
您需要登录后才可以回帖 登录 | 立即注册

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

GMT+8, 2025-12-17 20:30 , Processed in 0.149003 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

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