AI助手 – 自然语言生成期货回测工作流实践分享
  14771582611 2026年02月10日 131 0

初始策略构想

我向AI助手提出了一个相对经典的期货策略方向:“帮我构建一个基于双均线交叉的期货趋势跟踪策略,适用于螺纹钢主力合约,时间周期为日线,时间长度近两年”
fd32aefad41054365d3aa0a4c76c700c.png

AI助手生成工作流

8033c1683e6af6488dce0441487dd8fa.png

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助手生成

最后一次编辑于 2026年02月10日 0

暂无评论

推荐阅读