问题描述
请帮我写一个双均线交叉策略,当短期均线上穿长期均线时买入,下穿时卖出。
解决方案
这是一个基于 QMT 平台的双均线交叉(金叉买入,死叉卖出)策略。
策略逻辑
- 短期均线(Short MA):例如 5 日均线。
- 长期均线(Long MA):例如 20 日均线。
- 买入信号(金叉):当短期均线上穿长期均线时,全仓买入。
- 卖出信号(死叉):当短期均线下穿长期均线时,清仓卖出。
代码实现
# -*- coding: gbk -*-
import pandas as pd
import numpy as np
def init(ContextInfo):
"""
初始化函数,设定策略参数和变量
"""
# 策略参数设置
ContextInfo.short_period = 5 # 短期均线周期
ContextInfo.long_period = 20 # 长期均线周期
ContextInfo.account_id = 'YOUR_ACCOUNT_ID' # 【重要】请在此处替换您的资金账号
ContextInfo.account_type = 'STOCK' # 账号类型:'STOCK'股票, 'FUTURE'期货
# 设定股票池(这里以浦发银行为例,实际使用时可在界面设置或此处修改)
ContextInfo.set_universe(['600000.SH'])
# 费率设置(回测用,实盘无效)
ContextInfo.set_commission(0.0003) # 手续费万三
ContextInfo.set_slippage(1, 0.002) # 滑点 0.002元
def handlebar(ContextInfo):
"""
K线周期运行函数,每根K线执行一次
"""
# 获取当前正在运行的股票代码
stock_code = ContextInfo.stockcode
# 获取当前K线的索引位置
index = ContextInfo.barpos
# 如果当前K线数量不足以计算长期均线,则直接返回
if index < ContextInfo.long_period:
return
# 获取历史行情数据
# 取过去 long_period + 2 根K线的数据,保证有足够数据计算均线和判断交叉
# dividend_type='front' 表示使用前复权数据,防止分红除权影响均线形态
data = ContextInfo.get_market_data(
['close'],
stock_code=[stock_code],
count=ContextInfo.long_period + 5,
dividend_type='front'
)
# 如果数据获取失败或为空,直接返回
if data is None or data.empty:
return
# 提取收盘价序列 (Series格式)
close_prices = data['close']
# 计算均线
ma_short = close_prices.rolling(window=ContextInfo.short_period).mean()
ma_long = close_prices.rolling(window=ContextInfo.long_period).mean()
# 获取最近两个时间点的均线值
# -1 代表当前K线的值,-2 代表上一根K线的值
# 注意:在回测中,-1是当前回测到的时间点;在实盘中,-1是最新的一根K线
ma_short_curr = ma_short.iloc[-1]
ma_short_prev = ma_short.iloc[-2]
ma_long_curr = ma_long.iloc[-1]
ma_long_prev = ma_long.iloc[-2]
# 检查是否产生信号
# 金叉:上根K线短均线 < 长均线,且 当前K线短均线 > 长均线
golden_cross = (ma_short_prev < ma_long_prev) and (ma_short_curr > ma_long_curr)
# 死叉:上根K线短均线 > 长均线,且 当前K线短均线 < 长均线
death_cross = (ma_short_prev > ma_long_prev) and (ma_short_curr < ma_long_curr)
# 执行交易逻辑
# 使用 order_target_percent 接口,它会自动计算需要买卖的数量
# 1.0 代表调整仓位到 100%(全仓),0.0 代表调整仓位到 0%(清仓)
if golden_cross:
print(f"时间: {ContextInfo.get_bar_timetag(index)} | 信号: 金叉买入 | {stock_code}")
# 全仓买入
order_target_percent(stock_code, 1.0, ContextInfo, ContextInfo.account_id)
elif death_cross:
print(f"时间: {ContextInfo.get_bar_timetag(index)} | 信号: 死叉卖出 | {stock_code}")
# 清仓卖出
order_target_percent(stock_code, 0.0, ContextInfo, ContextInfo.account_id)
代码说明与注意事项
-
编码格式:
- 第一行
# -*- coding: gbk -*-是必须的,QMT 的 Python 编辑器默认使用 GBK 编码,否则中文注释会乱码或报错。
- 第一行
-
账号设置:
- 在
init函数中,ContextInfo.account_id = 'YOUR_ACCOUNT_ID'这一行必须修改为你实际的资金账号。
- 在
-
数据获取:
- 使用了
ContextInfo.get_market_data获取历史收盘价。 - 参数
dividend_type='front'设置为前复权。在均线策略中,复权非常重要,否则分红派息导致的股价缺口会产生错误的死叉信号。
- 使用了
-
交易函数:
- 使用了
order_target_percent。这是一个非常方便的高级函数:- 当信号为买入时,传入
1.0,系统会自动计算当前可用资金能买多少股,并下单买入。 - 当信号为卖出时,传入
0.0,系统会自动检查当前持仓,如果有持仓则全部卖出。
- 当信号为买入时,传入
- 如果你需要固定手数交易(例如每次买100股),可以使用
order_shares(stock_code, 100, ...)。
- 使用了
-
回测与实盘:
- 此代码既可用于回测,也可用于实盘(需在界面选择“运行”模式)。
- 在实盘模式下,
handlebar会随行情刷新。如果运行在日线周期,通常在收盘前或收盘后确认信号;如果运行在分钟线,则每根分钟线结束时确认信号。