一、修改的内容
将原来的 has_callback 和 has_rebound 简单布尔逻辑,替换为:
统计 cb_count(下跌根数)和 rb_count(上涨根数)。
has_callback = (cb_count >= 2) 。
has_rebound = (rb_count >= 2)(至少2根上涨,保持原有宽松条件,你可以根据需要自行增加限制)。
二、测试结果
1.策略研究
(1)纯碱9.24行情没有开单
20240826 00:00 ZCE|F|SA|609 买平 限价单 1 1579 31580.00 1 -280.00 1.00 0.00
20250220 00:00 ZCE|F|SA|609 买开 限价单 1 1532 30640.00 1 0.00 1.00 0.00

(2)棕榈的2022.6.9-6.28这一波大跌也没有开仓
不符合has_callback的条件。
20230529 00:00 DCE|F|P|2609 卖开 限价单 1 6694 66940.00 1 0.00 1.00 0.00
20230602 00:00 DCE|F|P|2609 买平 限价单 1 6470 64700.00 1 2240.00 1.00 0.00
20230725 00:00 DCE|F|P|2609 买开 限价单 1 7680 76800.00 1 0.00 1.00 0.00
20230728 00:00 DCE|F|P|2609 卖平 限价单 1 7654 76540.00 1 -260.00 1.00 0.00

2.代码
# 极智量化策略:MA10斜率 + 回调突破 + 动态止盈止损
# 适用周期:推荐1分钟、5分钟或日线
# 作者:量化交易高手
# 说明:
# 开多:MA10向上,价格在MA10之上,近3根K线内有回调(收盘低于前一根),
# 当前Bar收盘价突破前一根Bar高点。
# 开空:MA10向下,价格在MA10之下,近3根K线内有反弹(收盘高于前一根),
# 当前Bar收盘价跌破前一根Bar低点。
# 止损:多单止损为前一根Bar最低价 - 1个最小变动价位;
# 空单止损为前一根Bar最高价 + 1个最小变动价位。
# 止盈:多单平仓条件:MA10斜率转下 或 收盘价跌破前一根Bar低点;
# 空单平仓条件:MA10斜率转上 或 收盘价突破前一根Bar高点。
import talib
import numpy as np
# ----- 策略参数(可优化) -----
ma_len = 10 # 均线周期
max_cb = 3 # 允许的回调/反弹K线根数(此处用于检测是否有回调/反弹)
qty = 1 # 固定下单手数(可根据资金调整)
# ----- 策略初始化 -----
def initialize(context):
# 设置基准合约(建议通过界面添加合约,此处示例用郑商所白糖主连)
# 用户可改为自己的合约代码,或直接通过界面设置
# SetBarInterval('ZCE|Z|SR|MAIN', 'M', 1, 200)
# 若通过界面设置了合约,可注释掉上行,用界面合约作为基准
SetTriggerType(5) # K线触发(回测和实盘均适用)
SetOrderWay(2) # K线稳定后发单(推荐回测,实盘可改为1实时发单)
# 设置初始资金、手续费等(可选)
# SetInitCapital(1000000)
# SetTradeFee('A', 2, 5) # 固定手续费5元/手
# SetSlippage(1) # 滑点1跳
LogInfo("策略初始化完成,MA周期:%d,回调允许根数:%d" % (ma_len, max_cb))
# ----- 策略主逻辑 -----
def handle_data(context):
# 获取基准合约的K线数据(若需多合约,可自行扩展)
close = Close() ##获取当前基准合约、基准周期的所有收盘价历史序列(一个数组)
high = High()
low = Low()
# 确保数据足够计算均线
if len(close) < ma_len + 2:
return
# 计算10日均线
ma = talib.SMA(close, ma_len)
# 当前Bar索引(用于判断数据就绪)
bar_idx = CurrentBar()
if bar_idx < ma_len + 2:
return
# ---- 构造当前K线时间字符串(格式:YYYYMMDD HH:MM:SS) ----
date_str = str(Date())
t = Time()
# Time() 返回 0.HHMMSS,转换为整数秒
time_int = int(t * 1000000) # 例如 0.113421 -> 113421
hh = time_int // 10000
mm = (time_int // 100) % 100
ss = time_int % 100
cur_time_str = "%s %02d:%02d:%02d" % (date_str, hh, mm, ss)
# ---- 获取关键价格 ----
cur_close = close[-1]
cur_high = high[-1]
cur_low = low[-1]
prev_high = high[-2] # 前一根Bar最高价
prev_low = low[-2] # 前一根Bar最低价
ma_cur = ma[-1]
ma_prev = ma[-2]
# ---- 判断MA10斜率 ----
ma_up = ma_cur > ma_prev # 均线向上
ma_down = ma_cur < ma_prev # 均线向下
# ---- 判断价格与MA10的关系 ----
above_ma = cur_close > ma_cur
below_ma = cur_close < ma_cur
# ---- 检测近3根K线是否有回调(收盘低于前一根)或反弹(收盘高于前一根) ----
# 采用“层次一 + 层次二”组合:统计下跌/上涨根数 + 是否触及均线
cb_count = 0
rb_count = 0
if len(close) >= 4:
for i in range(1, 4): # i=1,2,3 分别对应前1、前2、前3根
if close[-i] < close[-i-1]:
cb_count += 1
if close[-i] > close[-i-1]:
rb_count += 1
# 回调:至少2根下跌
has_callback = (cb_count >= 2)
# 反弹:至少2根上涨 + 且没有真回踩(即价格一直在均线之上反弹),注意这里对反弹的判定也加上了“不触及均线”以区分回调
# 为简化,这里沿用原意:只要反弹根数>=2就算,但也可增加条件,这里按“层次一”处理,暂不加额外限制,仅使用根数
has_rebound = (rb_count >= 2)
# ---- 开仓信号 ----
# 多单开仓条件:MA向上,价格在MA之上,有回调(至少一根阴线),且当前收盘突破前一根高点
if ma_up and above_ma and has_callback and cur_close > prev_high:
if MarketPosition() == 0: # 无持仓时开多
Buy(qty, cur_close)
LogInfo("[%s] 开多仓,价格:%.2f,MA10:%.2f,前高:%.2f" % (cur_time_str, cur_close, ma_cur, prev_high))
# 记录止损价(前一根低点 - 1跳)
context.stop_loss = prev_low - PriceTick()
# 记录开仓价(用于止盈参考)
context.entry_price = cur_close
# 记录开仓时均线斜率
context.ma_up_at_entry = ma_up
# 空单开仓条件:MA向下,价格在MA之下,有反弹(至少一根阳线),且当前收盘跌破前一根低点
if ma_down and below_ma and has_rebound and cur_close < prev_low:
if MarketPosition() == 0:
SellShort(qty, cur_close)
LogInfo("[%s] 开空仓,价格:%.2f,MA10:%.2f,前低:%.2f" % (cur_time_str, cur_close, ma_cur, prev_low))
context.stop_loss = prev_high + PriceTick()
context.entry_price = cur_close
context.ma_up_at_entry = ma_up # 开空时记录当前斜率(应为False)
# ---- 持仓管理(止盈止损) ----
if MarketPosition() == 1: # 持多仓
# 止损:价格跌破止损价
if cur_close <= context.stop_loss:
Sell(0, cur_close) # 平多(数量0表示平全部)
LogInfo("[%s] 多仓止损,价格:%.2f,止损价:%.2f" % (cur_time_str, cur_close, context.stop_loss))
# 止盈条件1:MA斜率转下(反转走掉)
elif ma_down: # 均线由向上转为向下
Sell(0, cur_close)
LogInfo("[%s] 多仓止盈(均线转下),价格:%.2f" % (cur_time_str, cur_close))
# 止盈条件2:跌破前一根低点(涨不动了)
elif cur_close < low[-2]:
Sell(0, cur_close)
LogInfo("[%s] 多仓止盈(跌破前低),价格:%.2f,前低:%.2f" % (cur_time_str, cur_close, low[-2]))
# 其他情况可添加动态止盈(如移动止损),此处暂略
elif MarketPosition() == -1: # 持空仓
# 止损:价格突破止损价
if cur_close >= context.stop_loss:
BuyToCover(0, cur_close)
LogInfo("[%s] 空仓止损,价格:%.2f,止损价:%.2f" % (cur_time_str, cur_close, context.stop_loss))
# 止盈条件1:MA斜率转上(反转走掉)
elif ma_up:
BuyToCover(0, cur_close)
LogInfo("[%s] 空仓止盈(均线转上),价格:%.2f" % (cur_time_str, cur_close))
# 止盈条件2:突破前一根高点(涨不动了)
elif cur_close > high[-2]:
BuyToCover(0, cur_close)
LogInfo("[%s] 空仓止盈(突破前高),价格:%.2f,前高:%.2f" % (cur_time_str, cur_close, high[-2]))
# 可选:记录策略运行信息
# LogDebug("当前Bar:%d,收盘:%.2f,MA10:%.2f,持仓:%d" % (CurrentBar(), cur_close, ma_cur, MarketPosition()))
# ---- 绘制指标 ----
# 在主图上绘制MA10均线(红色)
PlotNumeric("MA10", ma_cur, RGB_Red())
# 在副图上绘制累计盈亏曲线(紫色,独立坐标)
PlotNumeric("Profit", NetProfit() + FloatProfit() - TradeCost(), RGB_Purple(), False, True)
# ----- 历史阶段结束回调(可选) -----
def hisover_callback(context):
# 平掉所有持仓(如果策略在历史结束时需要平仓)
if MarketPosition() == 1:
Sell(0, Close()[-1])
LogInfo("历史阶段结束,多仓平仓")
elif MarketPosition() == -1:
BuyToCover(0, Close()[-1])
LogInfo("历史阶段结束,空仓平仓")
LogInfo("历史回测结束")
# ----- 策略退出回调(可选) -----
def exit_callback(context):
LogInfo("策略退出")