3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
这是一个基于 Z-Score(标准分数) 的均值回归策略。
Z-Score 用于衡量当前价格偏离移动平均线多少个标准差。
以下代码适用于 QMT 的 Python 策略编辑器。代码包含了详细注释,并使用了 get_market_data_ex 获取数据,以及 order_target_percent 进行仓位管理。
# -*- coding: gbk -*-
import pandas as pd
import numpy as np
def init(ContextInfo):
"""
策略初始化函数
"""
# 设置策略参数
ContextInfo.period = 20 # 均线和标准差的计算周期
ContextInfo.threshold = 2.0 # 开仓阈值(2倍标准差)
ContextInfo.exit_threshold = 0.5 # 平仓阈值(回归到0.5倍标准差以内)
# 设置交易账号(请替换为您自己的资金账号)
# ContextInfo.set_account('您的资金账号')
# 设定股票池(这里以沪深300ETF为例,也可以在界面上选择运行品种)
ContextInfo.target_stock = '510300.SH'
ContextInfo.set_universe([ContextInfo.target_stock])
# 策略运行变量
ContextInfo.holding_side = 0 # 0:空仓, 1:多头, -1:空头
def handlebar(ContextInfo):
"""
K线周期运行函数
"""
# 获取当前主图或设置的标的代码
stock_code = ContextInfo.target_stock
# 获取当前K线索引
index = ContextInfo.barpos
# 获取历史行情数据
# 我们需要 period 个数据来计算均值,为了稳健多取一点
count = ContextInfo.period + 5
# 使用 get_market_data_ex 获取数据 (推荐接口)
# 注意:subscribe=True 确保实盘时数据自动更新
data_map = ContextInfo.get_market_data_ex(
['close'],
[stock_code],
period=ContextInfo.period,
count=count,
subscribe=True
)
if stock_code not in data_map:
return
# 获取收盘价序列 (pandas DataFrame)
df = data_map[stock_code]
# 确保数据量足够计算
if len(df) < ContextInfo.period:
return
# 提取收盘价 Series
close_series = df['close']
# --- 计算 Z-Score ---
# 1. 计算 N 日移动平均线 (MA)
ma = close_series.rolling(window=ContextInfo.period).mean()
# 2. 计算 N 日标准差 (Std)
std = close_series.rolling(window=ContextInfo.period).std()
# 3. 计算 Z-Score
# Z = (当前价格 - 均值) / 标准差
z_score_series = (close_series - ma) / std
# 获取当前最新的 Z-Score 值
current_z = z_score_series.iloc[-1]
# 如果计算结果无效(如NaN),则跳过
if np.isnan(current_z):
return
# --- 绘图 (可选) ---
# 在副图画出 Z-Score,方便观察
ContextInfo.paint('Z_Score', current_z, -1, 0)
ContextInfo.paint('Upper', ContextInfo.threshold, -1, 0, 'red')
ContextInfo.paint('Lower', -ContextInfo.threshold, -1, 0, 'green')
# --- 交易逻辑 ---
# 1. 开空/卖出信号:价格偏离均值过高 (Z > 2.0)
if current_z > ContextInfo.threshold:
# 如果当前不是空头,则做空
# 注意:股票账户通常只能卖出持仓(Target=0),期货/融券账户可以做空(Target<0)
# 这里演示设为 0% (清仓/卖出),如果是期货可设为 -0.5
print(f"Z-Score: {current_z:.2f} > {ContextInfo.threshold}, 触发卖出/做空信号")
order_target_percent(stock_code, 0.0, ContextInfo, ContextInfo.get_account(0))
ContextInfo.holding_side = 0 # 标记状态
# 2. 开多/买入信号:价格偏离均值过低 (Z < -2.0)
elif current_z < -ContextInfo.threshold:
# 如果当前不是多头,则做多
# 目标仓位设为 50%
print(f"Z-Score: {current_z:.2f} < -{ContextInfo.threshold}, 触发买入/做多信号")
order_target_percent(stock_code, 0.5, ContextInfo, ContextInfo.get_account(0))
ContextInfo.holding_side = 1
# 3. 平仓/回归信号:价格回归均值附近 (|Z| < 0.5)
elif abs(current_z) < ContextInfo.exit_threshold:
# 如果当前持有头寸,则平仓
if ContextInfo.holding_side != 0:
print(f"Z-Score: {current_z:.2f} 回归均值, 平仓")
order_target_percent(stock_code, 0.0, ContextInfo, ContextInfo.get_account(0))
ContextInfo.holding_side = 0
数据获取 (get_market_data_ex):
subscribe=True 非常重要,它保证了在实盘运行时,策略能自动订阅并接收最新的行情推送。指标计算 (Pandas Rolling):
rolling(window=N).mean() 和 rolling(window=N).std() 来高效计算移动平均和标准差。交易执行 (order_target_percent):
order_target_percent(stock, target, ...) 是一个非常方便的函数。0.0 到 1.0(即只能做多或平仓)。代码中 Z > Threshold 时设置为 0.0 即代表卖出平仓。-0.5)来实现真正的反向开空。绘图 (paint):
ContextInfo.paint,运行策略时,你可以在副图看到 Z-Score 的曲线变化,便于验证策略逻辑。init 函数中,将 ContextInfo.set_account 的注释取消,并填入你的真实资金账号(回测模式下不需要)。Q: 为什么 get_market_data_ex 返回的数据有时候是空的?
A: 请检查 ContextInfo.set_universe 是否设置了对应的股票,或者在界面上是否选择了正确的品种。另外,如果是回测,请确保本地已经下载了对应的历史数据(在数据管理中补充数据)。
Q: 如何实现真正的“做空”?
A: 在代码的 Z > Threshold 分支中,将 order_target_percent 的第二个参数设置为负数(例如 -0.5)。前提是你绑定的账号支持做空(如期货账号或两融账号)。
Q: 这里的 Z-Score 是基于收盘价计算的吗?
A: 是的,代码中使用 df['close'],即基于收盘价计算。如果需要基于盘中实时价格,逻辑是一样的,因为 handlebar 在实盘中会随每个 Tick 更新,iloc[-1] 取到的就是最新价。