问题描述
解决方案
这是一个非常实用的风控思路,即**“大盘择时”**。在量化交易中,我们通常引入一个基准指数(如沪深300、上证指数)来代表“市场”。
判断牛熊最简单且有效的方法是使用均线(Moving Average):
- 牛市定义:基准指数的当前价格 大于 其 N 日均线(例如 20日或 60日均线)。
- 熊市定义:基准指数的当前价格 小于 其 N 日均线。
策略逻辑
- 基准:选取 沪深300指数 (000300.SH) 代表大盘。
- 指标:计算沪深300的 20日均线 (MA20)。
- 判断:
- 若
沪深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)
代码关键点解析
-
get_market_data_ex:- 这是 QMT 获取行情的推荐接口。我们用它获取
000300.SH的历史收盘价。 count=ContextInfo.ma_period + 1是为了确保计算均线时有足够的数据点。
- 这是 QMT 获取行情的推荐接口。我们用它获取
-
牛熊判断逻辑:
benchmark_current_price > benchmark_ma: 这是一个经典的趋势跟踪逻辑。- 如果大盘站上均线,认为市场情绪向好(牛市),允许策略开仓。
- 如果大盘跌破均线,认为市场风险较高(熊市),策略强制平仓或停止买入。
-
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_ex 和 get_market_data 有什么区别?
A: get_market_data_ex 是 QMT 的新版行情接口,返回的数据结构更清晰(Pandas DataFrame),且支持更多参数(如复权方式、订阅开关),建议优先使用。
Q: 这个策略在回测和实盘中都能用吗?
A: 是的。QMT 的 API 设计保证了同一套代码可以在回测和实盘模式下运行。但在实盘前,请务必在模拟盘中验证逻辑,并检查 ContextInfo.account_id 是否配置正确。