一、螺纹钢回测效果:


可以显示均线:

代码:
备注:
如果回测结果只显示3年,那时因为 SetBarInterval这里的问题。
# 策略名称:双均线策略(5日上穿20日做多,下穿做空)+ 均线显示
# 适用周期:日线
# 策略逻辑:
# 金叉(5日均线上穿20日均线)→ 开多仓
# 死叉(5日均线下穿20日均线)→ 开空仓
# 同时在K线图上绘制5日和20日均线
import numpy as np
import talib
# -------------------- 初始化函数 --------------------
def initialize(context):
# 获取当前基准合约,订阅日线数据
contract = Symbol()
#SetBarInterval(contract, 'D', 1, 500) # 日线,500根K线
SetBarInterval(contract, 'D', 1, 'A') #使用所有可用历史数据
# 设置初始资金
SetInitCapital(1000000)
# 发单方式:K线完成后发单
SetOrderWay(2)
# 交易方向:双向
SetTradeDirection(0)
# 设置滑点
SetSlippage(1)
# 设置日志级别
SetLogLevel(2)
# 定义均线周期参数
context.fast_period = 5 # 快速均线周期
context.slow_period = 20 # 慢速均线周期
# 定义状态变量(用于记录上一次信号,避免重复发单)
context.last_signal = 0 # 0:无信号, 1:金叉(做多), -1:死叉(做空)
# -------------------- 核心策略函数 --------------------
def handle_data(context):
# 获取日线收盘价数据(numpy数组)
close = Close()
# 检查数据长度是否足够
if len(close) < context.slow_period + 1:
LogInfo("数据不足,等待...")
return
# 计算5日和20日简单移动平均线
ma_fast = talib.SMA(close, context.fast_period)
ma_slow = talib.SMA(close, context.slow_period)
# 获取当前最新值
current_ma_fast = ma_fast[-1]
current_ma_slow = ma_slow[-1]
prev_ma_fast = ma_fast[-2]
prev_ma_slow = ma_slow[-2]
current_close = close[-1]
# ========== 绘制均线到K线图(新增部分)==========
# PlotNumeric(名称, 数值, 颜色, 是否主图)
# 第4个参数为False表示绘制在主图上(与K线叠加)[reference:1]
PlotNumeric("MA5", current_ma_fast, RGB_Red(), False) # 红色5日均线
PlotNumeric("MA20", current_ma_slow, RGB_Blue(), False) # 蓝色20日均线
# ================================================
# 判断金叉和死叉
# 金叉:今日快线 > 慢线 且 昨日快线 <= 慢线
golden_cross = (current_ma_fast > current_ma_slow) and (prev_ma_fast <= prev_ma_slow)
# 死叉:今日快线 < 慢线 且 昨日快线 >= 慢线
dead_cross = (current_ma_fast < current_ma_slow) and (prev_ma_fast >= prev_ma_slow)
# 获取当前持仓状态
pos = MarketPosition() # 1:多头, -1:空头, 0:无持仓
# -------------------- 交易逻辑 --------------------
# 【金叉做多】5日均线上穿20日均线
if golden_cross and pos <= 0:
qty = 1
Buy(qty, current_close)
LogInfo("【金叉】5日均线(%.2f)上穿20日均线(%.2f),开多仓1手,价格:%.2f" %
(current_ma_fast, current_ma_slow, current_close))
context.last_signal = 1
# 【死叉做空】5日均线下穿20日均线
elif dead_cross and pos >= 0:
qty = 1
SellShort(qty, current_close)
LogInfo("【死叉】5日均线(%.2f)下穿20日均线(%.2f),开空仓1手,价格:%.2f" %
(current_ma_fast, current_ma_slow, current_close))
context.last_signal = -1
核对:


发现有差异:
原来是:
核心结论
回测阶段:无论代码中设置 SetOrderWay(1) 还是 SetOrderWay(2),发单方式统一为"K线稳定后发单",即当前K线走完后触发。
实盘阶段:SetOrderWay(2) 才真正生效——等K线走完、下一根K线开始时才发单。
如果您希望在回测中模拟实盘"K线稳定后发单"的延迟效果(即信号日次日开盘才成交),可以使用以下方式:
# 在 handle_data 中使用延迟发单
# 用全局变量记录信号,延迟一根Bar执行
def initialize(context):
context.pending_signal = 0 # 0:无, 1:做多, -1:做空
context.signal_price = 0.0
def handle_data(context):
# ... 计算均线和判断金叉死叉 ...
# 如果上一根Bar有信号,现在执行
if context.pending_signal == 1 and pos <= 0:
Buy(1, open[-1]) # 以今日开盘价成交
context.pending_signal = 0
elif context.pending_signal == -1 and pos >= 0:
SellShort(1, open[-1])
context.pending_signal = 0
# 当前Bar产生新信号,记录到下一根执行
if golden_cross:
context.pending_signal = 1
context.signal_price = close[-1]
elif dead_cross:
context.pending_signal = -1
context.signal_price = close[-1]
这样再和快期3的k线图对比,基本上就可以对得上了(差1个点或者2个点)
二、沪铜

三、豆粕
