🚀 AI 一键生成 qmt 策略代码

如何在 QMT 策略中加入市场牛熊状态判断,提升胜率?

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

问题描述

怎么判断当前市场是牛市还是熊市,然后让我的策略只在牛市的时候才买入?

解决方案

这是一个非常实用的风控思路,即**“大盘择时”**。在量化交易中,我们通常引入一个基准指数(如沪深300、上证指数)来代表“市场”。

判断牛熊最简单且有效的方法是使用均线(Moving Average)

  1. 牛市定义:基准指数的当前价格 大于 其 N 日均线(例如 20日或 60日均线)。
  2. 熊市定义:基准指数的当前价格 小于 其 N 日均线。

策略逻辑

  1. 基准:选取 沪深300指数 (000300.SH) 代表大盘。
  2. 指标:计算沪深300的 20日均线 (MA20)
  3. 判断
    • 沪深300收盘价 > 沪深300 MA20 -> 牛市 -> 允许买入或持有标的股票。
    • 沪深300收盘价 < 沪深300 MA20 -> 熊市 -> 禁止买入,并清仓手中持有的标的股票(防守策略)。

下面是完整的 QMT 策略代码实现:

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

def init(ContextInfo):
    # 1. 设置资金账号 (请修改为您的实际账号)
    ContextInfo.account_id = '6000000000' 
    ContextInfo.account_type = 'STOCK'
    ContextInfo.set_account(ContextInfo.account_id)
    
    # 2. 设置策略参数
    ContextInfo.benchmark = '000300.SH'  # 大盘基准:沪深300
    ContextInfo.target_stock = '600519.SH' # 交易标的:贵州茅台(示例)
    ContextInfo.ma_period = 20           # 牛熊分界线:20日均线
    
    # 3. 设置股票池 (用于回测和数据下载)
    ContextInfo.set_universe([ContextInfo.benchmark, ContextInfo.target_stock])

def handlebar(ContextInfo):
    # 获取当前K线位置,避免在数据不足时计算
    index = ContextInfo.barpos
    if index < ContextInfo.ma_period:
        return

    # --- 第一步:获取大盘(沪深300)的历史数据 ---
    # 获取过去 ma_period + 2 天的数据,确保均线计算有足够样本
    # 注意:get_market_data_ex 返回的是字典 {code: dataframe}
    market_data = ContextInfo.get_market_data_ex(
        fields=['close'], 
        stock_code=[ContextInfo.benchmark], 
        period='1d', 
        count=ContextInfo.ma_period + 1,
        dividend_type='follow'
    )
    
    if ContextInfo.benchmark not in market_data:
        return
        
    benchmark_df = market_data[ContextInfo.benchmark]
    
    # 如果数据长度不足,不进行计算
    if len(benchmark_df) < ContextInfo.ma_period:
        return

    # --- 第二步:计算大盘指标判断牛熊 ---
    # 获取大盘最新收盘价
    benchmark_current_price = benchmark_df.iloc[-1]['close']
    
    # 计算大盘均线 (取最近 ma_period 天的收盘价平均值)
    # 使用 iloc[-ContextInfo.ma_period:] 确保取的是最后N天
    benchmark_ma = benchmark_df['close'].iloc[-ContextInfo.ma_period:].mean()
    
    # 判断牛熊
    is_bull_market = benchmark_current_price > benchmark_ma
    
    # 打印调试信息 (方便在日志中查看当前状态)
    timetag = ContextInfo.get_bar_timetag(index)
    date_str = timetag_to_datetime(timetag, '%Y-%m-%d')
    market_status = "牛市" if is_bull_market else "熊市"
    print(f"日期: {date_str} | 大盘: {benchmark_current_price:.2f} | 大盘均线: {benchmark_ma:.2f} | 状态: {market_status}")

    # --- 第三步:执行交易逻辑 ---
    
    # 获取标的股票的持仓信息
    position = 0
    positions = get_trade_detail_data(ContextInfo.account_id, ContextInfo.account_type, 'POSITION')
    for pos in positions:
        if pos.m_strInstrumentID + '.' + pos.m_strExchangeID == ContextInfo.target_stock:
            position = pos.m_nVolume
            break

    # 策略分支
    if is_bull_market:
        # === 牛市逻辑 ===
        # 这里可以加入更细致的选股逻辑,本例简化为:如果是牛市且空仓,就全仓买入
        if position == 0:
            print(f"检测到牛市,买入 {ContextInfo.target_stock}")
            # 使用 order_target_value 调整持仓市值,这里示例买入 10万元
            # 注意:实盘中请确保有足够资金,或使用 order_target_percent
            order_target_value(ContextInfo.target_stock, 100000, ContextInfo, ContextInfo.account_id)
            
    else:
        # === 熊市逻辑 ===
        # 熊市只卖不买,如果有持仓则清仓
        if position > 0:
            print(f"检测到熊市,清仓 {ContextInfo.target_stock}")
            order_target_value(ContextInfo.target_stock, 0, ContextInfo, ContextInfo.account_id)

代码关键点解析

  1. get_market_data_ex:

    • 这是 QMT 获取行情的推荐接口。我们用它获取 000300.SH 的历史收盘价。
    • count=ContextInfo.ma_period + 1 是为了确保计算均线时有足够的数据点。
  2. 牛熊判断逻辑:

    • benchmark_current_price > benchmark_ma: 这是一个经典的趋势跟踪逻辑。
    • 如果大盘站上均线,认为市场情绪向好(牛市),允许策略开仓。
    • 如果大盘跌破均线,认为市场风险较高(熊市),策略强制平仓或停止买入。
  3. order_target_value:

    • 这是一个非常方便的交易函数。
    • order_target_value(stock, 100000, ...): 无论当前持仓多少,买入或卖出直到持仓市值达到 10万。
    • order_target_value(stock, 0, ...): 无论当前持仓多少,全部卖出直到持仓为 0(即清仓)。

如何优化?

  • 均线参数:20日线比较灵敏,适合短线;如果是中长线策略,可以改为 60日(季线)或 120日(半年线)。
  • 双均线确认:可以使用“金叉”逻辑(如大盘 5日均线 > 20日均线)来确认牛市,比单纯看价格更稳定。
  • 成交量辅助:在判断牛市时,可以加入“大盘成交量放大”作为辅助条件。

Q&A

Q: 为什么使用沪深300作为基准?
A: 沪深300指数包含了上海和深圳市场市值最大、流动性最好的300只股票,最能代表A股市场的整体走势。如果你的策略主要交易小盘股,也可以考虑使用中证500或中证1000作为基准。

Q: get_market_data_exget_market_data 有什么区别?
A: get_market_data_ex 是 QMT 的新版行情接口,返回的数据结构更清晰(Pandas DataFrame),且支持更多参数(如复权方式、订阅开关),建议优先使用。

Q: 这个策略在回测和实盘中都能用吗?
A: 是的。QMT 的 API 设计保证了同一套代码可以在回测和实盘模式下运行。但在实盘前,请务必在模拟盘中验证逻辑,并检查 ContextInfo.account_id 是否配置正确。