🚀 AI 一键生成 qmt 策略代码

QMT 平台如何实现抛物线转向 (Parabolic SAR) 止损与反转策略?

qmt | 发布时间: 2025/12/18
以下内容由 EasyQuant 生成。

问题描述

请帮我编写一个使用 Parabolic SAR 指标的交易策略

解决方案

这是一个基于 QMT 平台 API 编写的 Parabolic SAR (抛物线转向指标) 交易策略。

策略逻辑说明

  1. 指标原理:Parabolic SAR (Stop and Reverse) 是一种趋势跟踪指标。
    • 当股价位于 SAR 点位 上方 时,视为多头趋势(看涨)。
    • 当股价位于 SAR 点位 下方 时,视为空头趋势(看跌)。
  2. 交易信号
    • 买入信号:收盘价从下方突破 SAR 值(金叉)。
    • 卖出信号:收盘价从上方跌破 SAR 值(死叉)。
  3. 参数设置
    • 加速因子 (AF):初始 0.02,步长 0.02。
    • 最大加速因子 (Max AF):0.2。

策略代码

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

def init(ContextInfo):
    """
    策略初始化函数
    """
    # 设置资金账号 (请替换为您真实的资金账号)
    ContextInfo.accID = '6000000000' 
    ContextInfo.set_account(ContextInfo.accID)
    
    # 设置标的股票 (示例:浦发银行)
    ContextInfo.stock_code = '600000.SH'
    ContextInfo.set_universe([ContextInfo.stock_code])
    
    # 策略参数设置
    ContextInfo.sar_acceleration = 0.02  # 加速因子初始值和步长
    ContextInfo.sar_maximum = 0.2        # 加速因子最大值
    
    # 每次交易数量
    ContextInfo.trade_vol = 100
    
    print("SAR 策略初始化完成")

def handlebar(ContextInfo):
    """
    K线周期运行函数
    """
    # 获取当前图表的当前K线索引
    index = ContextInfo.barpos
    
    # 获取当前时间戳
    realtime = ContextInfo.get_bar_timetag(index)
    
    # 获取标的代码
    stock = ContextInfo.stock_code
    
    # 获取历史行情数据 (High, Low, Close)
    # 为了计算 SAR,我们需要一定长度的历史数据,这里取 100 根 K 线
    # 使用 get_market_data_ex 接口
    data_map = ContextInfo.get_market_data_ex(
        ['high', 'low', 'close'], 
        [stock], 
        period=ContextInfo.period, 
        count=100,
        dividend_type='front' # 前复权
    )
    
    if stock not in data_map:
        return
        
    df = data_map[stock]
    
    # 确保数据量足够计算指标
    if len(df) < 50:
        return

    # 提取 High 和 Low 用于计算 SAR
    high_prices = df['high'].values
    low_prices = df['low'].values
    close_prices = df['close'].values
    
    # 使用 talib 计算 SAR 指标
    # 注意:talib 接收 numpy array
    sar_values = talib.SAR(
        high_prices, 
        low_prices, 
        acceleration=ContextInfo.sar_acceleration, 
        maximum=ContextInfo.sar_maximum
    )
    
    # 获取当前和上一根K线的数据
    current_close = close_prices[-1]
    current_sar = sar_values[-1]
    
    prev_close = close_prices[-2]
    prev_sar = sar_values[-2]
    
    # 在图表上绘制 SAR 指标 (方便回测观察)
    ContextInfo.paint('SAR', current_sar, -1, 0, 'yellow')
    
    # ----------------------------------------------------------------
    # 交易逻辑判断
    # ----------------------------------------------------------------
    
    # 只有在最后一根K线或者是回测模式下才执行交易逻辑
    if not ContextInfo.is_last_bar():
        return

    # 获取当前持仓
    position = get_position(ContextInfo, stock)
    
    # 信号 1: 买入 (价格上穿 SAR)
    # 逻辑: 上一根K线收盘价在SAR下方,当前K线收盘价在SAR上方
    buy_signal = (prev_close < prev_sar) and (current_close > current_sar)
    
    # 信号 2: 卖出 (价格下穿 SAR)
    # 逻辑: 上一根K线收盘价在SAR上方,当前K线收盘价在SAR下方
    sell_signal = (prev_close > prev_sar) and (current_close < current_sar)
    
    # 执行买入
    if buy_signal:
        if position == 0:
            print(f"[{stock}] 触发买入信号: 价格({current_close}) 上穿 SAR({current_sar})")
            # 23: 买入, 1101: 单股单账号普通交易
            passorder(23, 1101, ContextInfo.accID, stock, 5, -1, ContextInfo.trade_vol, ContextInfo)
    
    # 执行卖出
    elif sell_signal:
        if position > 0:
            print(f"[{stock}] 触发卖出信号: 价格({current_close}) 下穿 SAR({current_sar})")
            # 24: 卖出, 1101: 单股单账号普通交易
            passorder(24, 1101, ContextInfo.accID, stock, 5, -1, position, ContextInfo)

def get_position(ContextInfo, stock_code):
    """
    辅助函数:获取指定股票的持仓数量
    """
    # 获取持仓对象列表
    # 'STOCK' 代表股票账户, 'POSITION' 代表持仓
    positions = get_trade_detail_data(ContextInfo.accID, 'STOCK', 'POSITION')
    
    for pos in positions:
        if pos.m_strInstrumentID + '.' + pos.m_strExchangeID == stock_code:
            return pos.m_nVolume
            
    return 0

代码关键点解析

  1. 数据获取 (get_market_data_ex)

    • SAR 指标计算依赖于最高价 (high) 和最低价 (low)。
    • 我们获取了最近 100 根 K 线的数据,以确保 talib.SAR 函数有足够的数据进行收敛计算。
    • 使用了 dividend_type='front'(前复权),这在回测和实盘中对于技术指标计算非常重要,可以避免分红派息导致的价格跳空影响指标准确性。
  2. 指标计算 (talib.SAR)

    • 利用 QMT 内置的 talib 库进行计算,效率高且准确。
    • 传入参数 acceleration (加速因子) 和 maximum (最大值) 是 SAR 的核心参数。
  3. 信号逻辑

    • 上穿 (金叉)prev_close < prev_sarcurrent_close > current_sar。这意味着趋势由跌转涨。
    • 下穿 (死叉)prev_close > prev_sarcurrent_close < current_sar。这意味着趋势由涨转跌。
  4. 绘图 (ContextInfo.paint)

    • 代码中加入了 ContextInfo.paint 函数,这样在回测或模型运行时,主图上会画出黄色的 SAR 点位,方便您直观验证策略信号是否正确。
  5. 交易执行 (passorder)

    • 买入使用 opType=23,卖出使用 opType=24
    • 下单价格类型 prType=5 (最新价),价格填 -1 表示跟随最新价。
    • 在下单前调用了自定义的 get_position 函数检查持仓,避免在没有持仓时卖出(虽然系统会报错,但逻辑上处理更好)。

如何使用

  1. 打开 QMT 客户端,进入【模型研究】或【策略编辑器】。
  2. 新建一个 Python 策略。
  3. 将上述代码完整复制粘贴进去。
  4. 修改 init 函数中的 ContextInfo.accID 为您的真实或模拟资金账号。
  5. 点击【编译】检查无误后,选择一个股票(如 600000.SH)和周期(如日线),点击【运行】或【回测】。

Q&A

Q: 为什么 SAR 指标在盘整震荡行情中表现不佳?
A: SAR 是典型的趋势跟踪指标。在明显的单边上涨或下跌趋势中,它能很好地锁住利润。但在横盘震荡时,价格频繁上下穿过 SAR 点位,会导致频繁发出买卖信号(来回止损),从而产生连续的小额亏损。通常建议结合 ADX (平均趋向指标) 来判断当前是否有趋势,只有在趋势明显时才使用 SAR。

Q: 如何修改 SAR 的灵敏度?
A: 可以调整 init 函数中的 ContextInfo.sar_acceleration (加速因子)。

  • 增大该值(例如 0.03):SAR 点位会更紧密地跟随价格,反应更灵敏,但假信号也会增加。
  • 减小该值(例如 0.01):SAR 点位跟随较慢,更能容忍价格波动,适合捕捉大趋势,但信号会有滞后。

Q: passorder 函数中的 1101 是什么意思?
A: 1101orderType(下单方式)的代码,代表:单股、单账号、普通、股/手方式下单。这是最常用的股票交易下单模式。如果您需要按金额下单(例如买入 1 万元),可以使用 1102