3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
这是一个基于 QMT 平台的量化交易策略代码。
talib 库计算 KDJ 指标(参数默认 9, 3, 3)。order_shares 进行下单。# -*- coding: gbk -*-
import pandas as pd
import numpy as np
import talib
def init(ContextInfo):
"""
初始化函数,策略启动时执行一次
"""
# 设置资金账号,请修改为您自己的资金账号
ContextInfo.account_id = '6000000000'
ContextInfo.set_account(ContextInfo.account_id)
# 策略参数设置
ContextInfo.kdj_n = 9
ContextInfo.kdj_m1 = 3
ContextInfo.kdj_m2 = 3
# 超卖阈值
ContextInfo.oversold_threshold = 20
# 每次交易数量
ContextInfo.trade_vol = 100
print("策略初始化完成")
def get_kdj(high, low, close, n, m1, m2):
"""
计算KDJ指标的辅助函数
"""
# 使用 talib 计算 K 和 D
# 注意:talib.STOCH 默认参数与国内常用的 KDJ 算法略有差异,这里使用通用设置
k, d = talib.STOCH(high, low, close,
fastk_period=n,
slowk_period=m1,
slowk_matype=0,
slowd_period=m2,
slowd_matype=0)
# 计算 J 值
j = 3 * k - 2 * d
return k, d, j
def handlebar(ContextInfo):
"""
K线处理函数,每根K线执行一次
"""
# 获取当前主图的股票代码
stock_code = ContextInfo.stockcode + '.' + ContextInfo.market
# ----------------------------------------------------------------
# 1. 获取日线数据 (用于判断超卖)
# ----------------------------------------------------------------
# 获取过去 100 天的数据以确保指标计算准确
daily_data = ContextInfo.get_market_data_ex(
['high', 'low', 'close'],
[stock_code],
period='1d',
count=100,
dividend_type='follow'
)
if stock_code not in daily_data or daily_data[stock_code].empty:
return
df_daily = daily_data[stock_code]
# 计算日线 KDJ
d_k, d_d, d_j = get_kdj(df_daily['high'].values,
df_daily['low'].values,
df_daily['close'].values,
ContextInfo.kdj_n,
ContextInfo.kdj_m1,
ContextInfo.kdj_m2)
# 获取最近一个完整的日线 K, D 值
# 注意:如果是盘中运行,-1 代表当天(未走完),-2 代表昨天。
# 策略逻辑:判断大趋势,通常看前一天的收盘状态,或者当天的实时状态。
# 这里取 -1 (最新值)
current_daily_k = d_k[-1]
current_daily_d = d_d[-1]
# 判断日线是否处于超卖区
is_daily_oversold = (current_daily_k < ContextInfo.oversold_threshold) and \
(current_daily_d < ContextInfo.oversold_threshold)
# ----------------------------------------------------------------
# 2. 获取 5分钟数据 (用于金叉买入)
# ----------------------------------------------------------------
# 策略应当运行在 5分钟 图上,或者显式获取 5分钟 数据
min5_data = ContextInfo.get_market_data_ex(
['high', 'low', 'close'],
[stock_code],
period='5m',
count=100,
dividend_type='follow'
)
if stock_code not in min5_data or min5_data[stock_code].empty:
return
df_5m = min5_data[stock_code]
# 计算 5分钟 KDJ
m_k, m_d, m_j = get_kdj(df_5m['high'].values,
df_5m['low'].values,
df_5m['close'].values,
ContextInfo.kdj_n,
ContextInfo.kdj_m1,
ContextInfo.kdj_m2)
# 获取 5分钟 KDJ 的当前值和前一值
curr_m_k = m_k[-1]
curr_m_d = m_d[-1]
prev_m_k = m_k[-2]
prev_m_d = m_d[-2]
# 判断 5分钟 金叉 (上根K线 K<D,当前K线 K>D)
is_5m_golden_cross = (prev_m_k < prev_m_d) and (curr_m_k > curr_m_d)
# 判断 5分钟 死叉 (用于卖出逻辑,可选)
is_5m_dead_cross = (prev_m_k > prev_m_d) and (curr_m_k < curr_m_d)
# ----------------------------------------------------------------
# 3. 交易逻辑执行
# ----------------------------------------------------------------
# 获取当前持仓 (简单示例,实际需根据 get_trade_detail_data 获取准确持仓)
# 这里仅做信号触发演示
# 信号 1: 买入
# 条件: 日线超卖 AND 5分钟金叉 AND 不是最后一根K线(回测时防止未来函数)
# 实盘时 ContextInfo.is_last_bar() 为 True,需要执行
if is_daily_oversold and is_5m_golden_cross:
print(f"时间: {ContextInfo.get_bar_timetag(ContextInfo.barpos)} - 触发买入信号: 日线超卖且5分钟金叉")
# 下单买入
order_shares(stock_code, ContextInfo.trade_vol, 'fix', df_5m['close'].iloc[-1], ContextInfo, ContextInfo.account_id)
# 信号 2: 卖出 (简单止盈/止损逻辑:5分钟死叉即卖出)
elif is_5m_dead_cross:
print(f"时间: {ContextInfo.get_bar_timetag(ContextInfo.barpos)} - 触发卖出信号: 5分钟死叉")
# 下单卖出
order_shares(stock_code, -ContextInfo.trade_vol, 'fix', df_5m['close'].iloc[-1], ContextInfo, ContextInfo.account_id)
ContextInfo.account_id = '6000000000' 需要修改为您实际的 QMT 资金账号。# -*- coding: gbk -*-,请勿删除。talib 库,QMT 内置环境中通常已包含此库。如果报错,可以使用 pandas 手动实现 KDJ 计算逻辑。handlebar 在实盘模式下,最后一根 K 线(当前正在波动的 K 线)每变动一次 tick 都会触发一次。ContextInfo.is_new_bar() 使用,或者使用 do_order 函数在下一根 K 线开盘时确认信号。上述代码使用的是即时信号逻辑。Q: 为什么使用 get_market_data_ex 而不是 get_market_data?
A: get_market_data_ex 是 QMT 较新的接口,返回的数据结构更清晰(字典包含 DataFrame),且支持订阅模式,效率更高。
Q: 如何避免实盘中信号闪烁导致的重复下单?
A: 可以在 handlebar 开头添加判断,只在 K 线走完时下单,或者使用全局变量记录当前 K 线是否已经交易过。最简单的方法是使用 passorder 的 quickTrade=0 参数(默认),它会在 K 线走完后才确认信号。
Q: 日线超卖的定义可以修改吗?
A: 可以。在 init 函数中修改 ContextInfo.oversold_threshold = 20 即可,例如改为 15 或 25。