3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
这是一个基于 ATR(平均真实波幅)指标的通道突破策略。
# -*- coding: gbk -*-
import pandas as pd
import numpy as np
def init(ContextInfo):
"""
策略初始化函数
"""
# --- 策略参数设置 ---
ContextInfo.stock_code = '600000.SH' # 标的股票:浦发银行
ContextInfo.period = 20 # ATR 和 均线的计算周期
ContextInfo.multiplier = 2.0 # 通道宽度乘数 (上轨 = MA + multiplier * ATR)
ContextInfo.account_id = 'YOUR_ACCOUNT_ID' # 请替换为您的资金账号
ContextInfo.trade_qty = 100 # 每次交易数量
# --- 设置股票池 ---
ContextInfo.set_universe([ContextInfo.stock_code])
# --- 设置交易账号 ---
ContextInfo.set_account(ContextInfo.account_id)
def get_position(ContextInfo, stock_code):
"""
获取当前持仓数量的辅助函数
"""
try:
# 获取持仓对象列表
positions = get_trade_detail_data(ContextInfo.account_id, 'stock', 'position')
for pos in positions:
if pos.m_strInstrumentID + '.' + pos.m_strExchangeID == stock_code:
return pos.m_nVolume
return 0
except Exception as e:
print("获取持仓失败: ", e)
return 0
def calculate_atr_bands(df, period, multiplier):
"""
计算 ATR 和 通道上下轨
"""
# 1. 计算 TR (True Range)
# TR = Max(High-Low, Abs(High-PreClose), Abs(Low-PreClose))
df['high_low'] = df['high'] - df['low']
df['pre_close'] = df['close'].shift(1)
df['high_pre_close'] = abs(df['high'] - df['pre_close'])
df['low_pre_close'] = abs(df['low'] - df['pre_close'])
df['tr'] = df[['high_low', 'high_pre_close', 'low_pre_close']].max(axis=1)
# 2. 计算 ATR (简单移动平均)
df['atr'] = df['tr'].rolling(window=period).mean()
# 3. 计算中轨 (MA)
df['mid'] = df['close'].rolling(window=period).mean()
# 4. 计算上下轨
df['upper'] = df['mid'] + (multiplier * df['atr'])
df['lower'] = df['mid'] - (multiplier * df['atr'])
return df
def handlebar(ContextInfo):
"""
K线周期运行函数
"""
# 获取当前 Bar 的索引
index = ContextInfo.barpos
stock_code = ContextInfo.stock_code
# 获取历史行情数据 (取足够多的数据以计算指标,例如 period + 10)
# 注意:get_market_data_ex 返回的是字典 {code: dataframe}
data_count = ContextInfo.period + 10
market_data = ContextInfo.get_market_data_ex(
['open', 'high', 'low', 'close'],
[stock_code],
period='1d',
count=data_count,
dividend_type='front' # 前复权
)
if stock_code not in market_data:
return
df = market_data[stock_code]
# 数据量不足时不计算
if len(df) < ContextInfo.period + 1:
return
# 计算指标
df = calculate_atr_bands(df, ContextInfo.period, ContextInfo.multiplier)
# 获取最新完成的一根K线的数据(用于生成信号)
# 注意:实盘中通常使用上一根K线的收盘价来决定是否在当前时刻交易,避免未来函数
last_bar = df.iloc[-2] # 上一根K线(已走完)
curr_bar = df.iloc[-1] # 当前K线(正在进行)
# 获取当前持仓
current_pos = get_position(ContextInfo, stock_code)
# --- 交易逻辑 ---
# 1. 买入信号:上一根K线收盘价突破上轨
if last_bar['close'] > last_bar['upper']:
if current_pos == 0:
print(f"时间: {curr_bar.name}, 价格突破上轨,买入开仓。收盘价: {last_bar['close']}, 上轨: {last_bar['upper']}")
# 23: 买入, 1101: 单股单账号普通下单, 5: 最新价
passorder(23, 1101, ContextInfo.account_id, stock_code, 5, -1, ContextInfo.trade_qty, ContextInfo)
# 2. 卖出信号:上一根K线收盘价跌破下轨
elif last_bar['close'] < last_bar['lower']:
if current_pos > 0:
print(f"时间: {curr_bar.name}, 价格跌破下轨,卖出平仓。收盘价: {last_bar['close']}, 下轨: {last_bar['lower']}")
# 24: 卖出
passorder(24, 1101, ContextInfo.account_id, stock_code, 5, -1, current_pos, ContextInfo)
# --- (可选) 绘图 ---
# 在回测界面绘制指标
ContextInfo.paint('Upper', last_bar['upper'], -1, 0, 'red')
ContextInfo.paint('Lower', last_bar['lower'], -1, 0, 'green')
ContextInfo.paint('Mid', last_bar['mid'], -1, 0, 'white')
# -*- coding: gbk -*-:
get_market_data_ex:
period + 10 条数据,确保有足够的数据来计算移动平均和 ATR。ATR 计算逻辑:
信号生成 (iloc[-2]):
handlebar 中,df.iloc[-1] 通常代表当前正在跳动的 K 线(未走完)。df.iloc[-2]) 的收盘价来判断是否突破。交易函数 passorder:
23 代表买入,24 代表卖出。1101 代表单股、单账号、按股数下单。5 代表使用最新价下单(市价单的一种模拟,实盘中可能需要根据流动性调整为对手价等)。ContextInfo.account_id 为你实际的资金账号。Q: 如何调整通道的灵敏度?
A: 修改 init 函数中的 ContextInfo.period (周期) 和 ContextInfo.multiplier (乘数)。
period 或 multiplier 会使通道变宽,交易信号变少,但可能过滤掉震荡。Q: 为什么使用 get_market_data_ex 而不是 get_market_data?
A: get_market_data_ex 是 QMT 的新版接口,返回的数据结构更规范(Pandas DataFrame),处理多只股票和多字段时更方便,且性能更好。
Q: 这个策略可以用于期货吗?
A: 逻辑上可以,但需要修改下单函数 passorder 的参数。期货涉及开仓(0/3)和平仓(1/2/4/5),且需要区分多空方向,而股票通常只有买入(23)和卖出(24)。