初始策略构想
我向AI助手提出了一个相对经典的期货策略方向:“帮我构建一个基于双均线交叉的期货趋势跟踪策略,适用于螺纹钢主力合约,时间周期为日线,时间长度近两年”
AI助手生成工作流
AI助手生成策略代码
AI助手生成的代码符合最基本的策略需求,有具体策略初始化代码块initialize和逻辑实现代码块handle_data
def initialize(context):
"""策略初始化
日线级别螺纹钢主力合约双均线趋势跟踪:
- 使用 RB_DOMINANT.SHF 获取每日主力真实合约
- 在 handle_data 中,针对当日主力合约做双均线判断和交易
"""
# 回测账户(期货)
context.account = "5588"
# 螺纹钢主力标的(用来查询主力合约)
context.underlying_symbol = "RB_DOMINANT.SHF"
# 双均线参数(可根据需要调整)
context.short_window = 20 # 短期均线
context.long_window = 60 # 长期均线
# 最近两年回测逻辑主要在回测引擎配置中设置起止日期即可
# 价格缓存:按真实合约维度维护历史收盘价
# 结构:{symbol: [close1, close2, ...]}
context.price_history = {}
# 当前交易合约(真实主力,如 RB2505.SHF)
context.current_symbol = None
# 订单ID列表,便于调试及可能的撤单扩展
context.order_ids = []
print("策略初始化完成")
print(f"账户: {context.account}")
print(f"主力查询标的: {context.underlying_symbol}")
print(f"短均线窗口: {context.short_window}, 长均线窗口: {context.long_window}")
def handle_data(context, data):
"""日线bar触发函数
逻辑:
1. 根据当前日期,通过 RB_DOMINANT.SHF 查询当日螺纹钢主力真实合约
2. 使用当日真实主力合约的收盘价更新该合约各自的历史价格
3. 当某真实合约的历史数据长度达到 long_window 时计算双均线
4. 无仓时:
- 短线上穿长线(金叉)则开多
- 短线下穿长线(死叉)则开空
有仓时:
- 多头遇死叉则平多
- 空头遇金叉则平空
5. 每日可能主力换月,但不做强制换仓,只对当日主力合约进行新决策
"""
trade_date = context.now # yyyymmdd
# 1. 获取当日螺纹钢主力真实合约代码
main_symbol = _get_main_contract_symbol(trade_date, context.underlying_symbol)
if main_symbol is None:
print(f"{trade_date} 未能获取螺纹钢主力合约,跳过")
return
context.current_symbol = main_symbol
# 从 data 中获取该合约的bar,如果当日未订阅该合约,直接返回
try:
bar = data[main_symbol]
except Exception:
print(f"{trade_date} data 中无 {main_symbol} 行情,跳过")
return
close_price = bar.close
if close_price is None or close_price <= 0:
print(f"{trade_date} {main_symbol} 收盘价无效: {close_price}")
return
# 2. 更新该合约的历史价格缓存
if main_symbol not in context.price_history:
context.price_history[main_symbol] = []
price_list = context.price_history[main_symbol]
price_list.append(close_price)
# 只保留最近 long_window 条数据
if len(price_list) > context.long_window:
price_list.pop(0)
# 3. 历史数据不足则直接返回
if len(price_list) < context.long_window:
print(f"{trade_date} {main_symbol} 历史数据不足: {len(price_list)}/" f"{context.long_window}")
return
# 4. 计算短期、长期均线
short_ma = float(np.mean(price_list[-context.short_window:]))
long_ma = float(np.mean(price_list))
print(
f"{trade_date} {main_symbol} 收盘价={close_price:.2f}, "
f"短均线({context.short_window})={short_ma:.2f}, "
f"长均线({context.long_window})={long_ma:.2f}"
)
# 5. 获取账户和该合约持仓
futures_account = context.future_account_dict.get(context.account)
if futures_account is None:
print(f"未找到期货账户 {context.account}")
return
positions = futures_account.positions
position = positions.get(main_symbol, None)
long_qty = 0
short_qty = 0
closable_long = 0
closable_short = 0
if position is not None:
long_qty = position.buy_quantity
short_qty = position.sell_quantity
closable_long = position.closable_buy_quantity
closable_short = position.closable_sell_quantity
has_long = long_qty > 0
has_short = short_qty > 0
# 计算简单的下单手数:账户总权益的1%名义价值
total_value = futures_account.total_value if futures_account.total_value is not None else 0
if total_value <= 0:
print("账户总权益无效,跳过交易")
return
# 获取合约乘数,用于大致控制杠杆
contract_multiplier = 10 # 默认
try:
mul_df = panda_data.get_future_list(symbol=[main_symbol], fields=["symbol", "contract_multiplier"], is_trading=None)
if mul_df is not None and not mul_df.empty:
contract_multiplier = float(mul_df.iloc[0]["contract_multiplier"])
except Exception as e:
print(f"获取合约乘数失败,使用默认10: {e}")
# 每次名义风险额度,示例设为账户总权益的1%
risk_ratio = 0.01
nominal_per_hand = contract_multiplier * close_price
if nominal_per_hand <= 0:
print("名义价值无效,跳过交易")
return
hands = int((total_value * risk_ratio) // nominal_per_hand)
if hands <= 0:
hands = 1
# 6. 信号判断与交易逻辑
# 无持仓 -> 产生开仓信号
from panda_backtest.backtest_common.type.order_type import MarketOrderStyle
if not has_long and not has_short:
# 短线上穿长线(趋势向上) -> 买入开仓
if short_ma > long_ma:
print(f"{trade_date} 金叉信号,多头开仓 {main_symbol} {hands} 手")
try:
order = buy_open(context.account, main_symbol, hands, style=MarketOrderStyle)[0]
if order:
context.order_ids.append(order.order_id)
print(f"买入开仓订单: {order.order_id}, 状态: {order.status}")
except Exception as e:
print(f"买入开仓失败: {e}")
# 短线下穿长线(趋势向下) -> 卖出开仓
elif short_ma < long_ma:
print(f"{trade_date} 死叉信号,空头开仓 {main_symbol} {hands} 手")
try:
order = sell_open(context.account, main_symbol, hands, style=MarketOrderStyle)[0]
if order:
context.order_ids.append(order.order_id)
print(f"卖出开仓订单: {order.order_id}, 状态: {order.status}")
except Exception as e:
print(f"卖出开仓失败: {e}")
else:
# 均线重合,不动作
pass
return
# 已持多头,遇死叉则平仓
if has_long and short_ma < long_ma and closable_long > 0:
print(f"{trade_date} 多头持仓遇死叉,平多 {main_symbol} {closable_long} 手")
try:
order = sell_close(context.account, main_symbol, closable_long, style=MarketOrderStyle)[0]
if order:
context.order_ids.append(order.order_id)
print(f"卖出平仓订单: {order.order_id}, 状态: {order.status}")
except Exception as e:
print(f"卖出平仓失败: {e}")
# 已持空头,遇金叉则平仓
if has_short and short_ma > long_ma and closable_short > 0:
print(f"{trade_date} 空头持仓遇金叉,平空 {main_symbol} {closable_short} 手")
try:
order = buy_close(context.account, main_symbol, closable_short, style=MarketOrderStyle)[0]
if order:
context.order_ids.append(order.order_id)
print(f"买入平仓订单: {order.order_id}, 状态: {order.status}")
except Exception as e:
print(f"买入平仓失败: {e}")
策略修改与应⽤
尝试让ai助手生成