问题描述
请帮我实现一个KDJ指标策略,当K线上穿D线形成金叉时买入,当K线下穿D线形成死叉时卖出。
解决方案
这是一个基于PTrade平台的KDJ指标交易策略。
策略逻辑
- 买入信号(金叉):当K线从下向上穿过D线(即上一周期 $K < D$ 且当前周期 $K > D$),且当前无持仓时,全仓买入。
- 卖出信号(死叉):当K线从上向下穿过D线(即上一周期 $K > D$ 且当前周期 $K < D$),且当前有持仓时,清仓卖出。
策略代码
def initialize(context):
"""
初始化函数,设置股票池、参数和手续费
"""
# 设置要操作的股票,这里以浦发银行(600000.SS)为例
g.security = '600000.SS'
set_universe(g.security)
# 设置KDJ指标参数 (默认 N=9, M1=3, M2=3)
g.N = 9
g.M1 = 3
g.M2 = 3
# 设置回测时的手续费(万分之三)和滑点
set_commission(commission_ratio=0.0003, min_commission=5.0)
set_slippage(slippage=0.002)
def handle_data(context, data):
"""
每日/每分钟运行的策略逻辑
"""
security = g.security
# 1. 获取历史数据
# 获取过去100根K线的数据,确保有足够的数据计算指标平滑值
# count=100 是为了保证计算结果的稳定性,虽然KDJ只需要9天,但递归计算需要更多历史数据
h = get_history(100, frequency='1d', field=['high', 'low', 'close'], security_list=security, fq='pre')
# 检查数据长度,防止数据不足导致报错
if h is None or len(h) < 100:
return
# 提取最高价、最低价、收盘价序列 (numpy array)
high_data = h['high'].values
low_data = h['low'].values
close_data = h['close'].values
# 2. 计算KDJ指标
# 直接调用PTrade内置的计算函数
k_values, d_values, j_values = get_KDJ(high_data, low_data, close_data, g.N, g.M1, g.M2)
# 获取当前和前一周期的K、D值
# -1 表示当前最新值,-2 表示前一周期值
curr_k = k_values[-1]
curr_d = d_values[-1]
prev_k = k_values[-2]
prev_d = d_values[-2]
# 3. 获取账户持仓和资金情况
# 获取当前标的的持仓数量
position = context.portfolio.positions[security].amount
# 获取当前可用现金
cash = context.portfolio.cash
# 4. 交易逻辑判断
# 判断金叉:前一周期 K < D,且当前周期 K > D
if prev_k < prev_d and curr_k > curr_d:
# 如果当前没有持仓,则买入
if position == 0:
# 使用所有可用资金买入
order_value(security, cash)
log.info("形成金叉 (K:%.2f, D:%.2f),买入 %s" % (curr_k, curr_d, security))
# 判断死叉:前一周期 K > D,且当前周期 K < D
elif prev_k > prev_d and curr_k < curr_d:
# 如果当前有持仓,则卖出
if position > 0:
# 卖出所有持仓 (目标持仓设为0)
order_target(security, 0)
log.info("形成死叉 (K:%.2f, D:%.2f),卖出 %s" % (curr_k, curr_d, security))
代码说明
get_history: 获取了过去100天的历史行情数据。虽然KDJ参数通常设为9,但为了让指标的平滑移动平均计算更接近主流软件的显示结果,建议读取较长的历史数据(如100条)。get_KDJ: 这是PTrade内置的技术指标计算函数,直接传入最高价、最低价和收盘价数组即可,无需手动编写公式。- 金叉与死叉判断: 通过比较当前时刻(
-1)和上一时刻(-2)的K值与D值的大小关系来判断交叉。 order_value与order_target: 分别用于按金额买入和调整持仓到目标数量(此处用于清仓)。
注意事项
- 该策略默认运行频率为日线。如果在回测界面选择分钟级别,
handle_data会每分钟运行一次,逻辑依然适用,但KDJ将变为分钟级别的KDJ。 - 代码中使用了
log.info来输出交易日志,方便您在回测结果页面的“日志”栏中查看买卖点触发情况。