回测策略实战检验
1.1 MACD
这段代码实现的是一个基于 MACD 指标的螺纹钢期货(RB2605.SHF)趋势跟随策略,核心逻辑如下:
初始化阶段(initialize):
设置期货账号 context.account = ‘5588’。
关注合约为 RB2605.SHF,保存到 context.future_contract。
定义 MACD 参数:短周期 12、长周期 26、信号线周期 9。
初始化一个空列表 context.historical_prices 用来保存历史收盘价。
每根 Bar 运行逻辑(handle_data):
1)数据获取与预处理
从当前 bar 中取出该合约的收盘价 close_price = bar[context.future_contract].close。
若收盘价为 0,则直接返回不交易。
将最新收盘价追加到 context.historical_prices。
若历史数据长度不足 long_window(26 根),则不计算 MACD,直接返回。
若历史数据长度大于 long_window,仅保留最近 26 个价格,保证计算窗口固定。
2)计算 MACD
使用 pandas 的 ewm 计算短周期 EMA 和长周期 EMA:
short_ema:12 期指数移动平均。
long_ema:26 期指数移动平均。
macd_line = short_ema - long_ema。
signal_line 是对 macd_line 再做 9 期 EMA。
取当前最新值:macd_current 和 signal_current。
3)账户与持仓信息
通过 context.future_account_dict.get(context.account) 获取期货账号信息 futures_account。
从 futures_account.positions 中查看该合约是否有仓位,以及多头 buy_quantity / 空头 sell_quantity。
4)无持仓时的开仓逻辑
条件:合约不在持仓中,或多头和空头数量都为 0。
若 macd_current > signal_current(MACD 上穿信号线,金叉):
按账户总权益的 5% 计算可开仓手数:hands = int(futures_account.total_value * 0.05 // close_price)。
若 hands > 0,执行 buy_open,市价开多。
若 macd_current < signal_current(MACD 下穿信号线,死叉):
同样按 5% 权益计算手数,执行 sell_open,市价开空。
5)有持仓时的平仓逻辑
获取当前持仓 position = futures_account.positions[context.future_contract]。
若出现死叉且当前有多头:
条件:macd_current < signal_current 且 position.buy_quantity > 0。
使用 sell_close 按 position.closable_buy_quantity 平掉多头仓位。
若出现金叉且当前有空头:
条件:macd_current > signal_current 且 position.sell_quantity > 0。
使用 buy_close 按 position.closable_sell_quantity 平掉空头仓位。
总结:策略是典型的单品种 MACD 趋势策略:
金叉:无仓则开多,有空则平空。
死叉:无仓则开空,有多则平多。
仓位大小与账户总权益成比例(固定 5%),根据当前价格折算为整数手数。
使用 EMA 计算 MACD,运行在事件驱动回测框架的 handle_data 中逐 bar 更新。
1.2 跨期套利
这段代码实现的是一个简单的白银期货跨期价差套利策略,核心逻辑如下:
初始化阶段(initialize):
指定期货账号:context.account = ‘5588’。
关注两只白银期货合约:AG2604.SHF 和 AG2602.SHF。
初始化一个价差序列 context.spread_list 用来记录每天两合约的价差。
设置价差相关阈值:
spread_threshold_open = 25:价差超过该值时考虑开仓。
spread_threshold_stop_loss = 30:价差绝对值超过该值时触发止损。
spread_threshold_stop_profit = 15:价差绝对值回到该值以内时触发止盈。
用 context.last_rebalance_date 记录最近一次调仓的日期,避免同一天重复执行。
每个bar回调逻辑(handle_data):
只在每天第一次触发时执行(通过 last_rebalance_date 控制)。
检查期货账号是否存在,获取账户总权益 total_value。
获取两只合约当前收盘价 close_price1 和 close_price2,跳过价格为0的异常情况。
计算当日价差 spread = close_price1 - close_price2,记录到 context.spread_list 并打印。
持仓与套利组合识别:
从 futures_account.positions 中查看当前是否已经持有套利组合:
一种情况:future1 做空(sell_quantity > 0),future2 做多(buy_quantity > 0)。
或反向:future1 做多,future2 做空。
如果已有套利组合:
不再新开仓,只根据当前价差判断是否需要平仓:
若 abs(spread) > 止损阈值 或 abs(spread) < 止盈阈值,调用 close_all_positions 平掉所有合约,并打印“止损/止盈平仓”。
无套利组合时的止损/止盈逻辑:
如果当前没有组合持仓,仍然有一段“价差止损/止盈判断”:
abs(spread) > spread_threshold_stop_loss:认为价差走极端,执行止损平仓(其实此时一般是空仓,更多是保护性逻辑)。
abs(spread) < spread_threshold_stop_profit:价差已经较小,执行止盈平仓(同样是保护性逻辑),然后返回,不开新仓。
开仓逻辑(构建价差组合):
先按账户总权益的 20% 计算每个合约的手数:
hands1 = int((total_value * 0.2) // close_price1)
hands2 = int((total_value * 0.2) // close_price2)
在 abs(spread) > spread_threshold_open 且手数都大于0时开仓:
若 close_price1 < close_price2:
认为合约1便宜、合约2贵 → 买入便宜的 AG2604,卖出贵的 AG2602(buy_open + sell_open)。
若 close_price1 > close_price2:
相反方向 → 卖出 AG2604,买入 AG2602。
形成一个跨期价差套利组合:多低空高或空高多低。
平仓函数(close_all_positions):
遍历期货账户当前所有持仓:
若有可平多头 closable_buy_quantity > 0,则用 sell_close 平多。
若有可平空头 closable_sell_quantity > 0,则用 buy_close 平空。
作用是“一键清空”所有期货持仓,多用于止盈、止损或退出策略。
整体而言:
策略每天只执行一次,根据两只白银期货的价差进行跨期套利:当价差足够大时做多便宜一边、做空贵的一边;当价差回归或进一步走极端时平仓止盈/止损。
持仓管理采取简单的“是否存在价差组合 → 是则只看平仓,不再加仓;否则按阈值新开仓”。