同一根 K 线多次开仓?用 on_bar_run 函数轻松解决

经常有朋友遇到这样的问题,在编写基于 K 线的策略时,明明只希望每根 K 线触发一次开仓,却出现 “同一根 K 线内多次开仓” 的情况,导致持仓数量异常,回测收益失真。这一问题的核心原因是策略逻辑写在了on_tick函数中,未过滤 “非新 K 线” 的 tick 数据。

1.为什么会多次开仓?

on_tick函数的触发频率与行情报价一致(通常 1 秒 2 次),若将 K 线开仓逻辑直接写在on_tick中,同一根 K 线产生的多个 tick 会反复执行开仓判断,导致多次开仓。例如 1 分钟 K 线存续期间,会有 120 次 tick 触发,若未做过滤,开仓逻辑会执行 120 次。

2.核心解决方案

用 on_bar_run 函数绑定 K 线逻辑期魔方提供on_bar_run函数,可将on_bar函数注册为 “仅新 K 线产生时执行”,避免同一根 K 线内重复触发。具体操作分为两步:
步骤 1:在on_tick函数中调用on_bar_run,指定 K 线处理函数(如on_bar);
步骤 2:将开仓、指标计算等 K 线相关逻辑写在on_bar函数中。

示例代码:

# 1. on_tick函数:仅负责触发on_bar_run
def on_tick(context):
    # 注册on_bar函数,仅新K线产生时执行
    on_bar_run(on_bar, context)

# 2. on_bar函数:编写K线相关逻辑(指标计算、开仓判断)
def on_bar(context):
    # 获取K线数据(仅新K线产生时更新)
    context.klines = get_kline(context.base_instrument_id, context.base_period, 60)
    context.close_array = context.klines.get("close")
    
    # 计算双均线(仅新K线产生时计算)
    context.ma5 = ta.SMA(np.asarray(context.close_array), 5)[:-1]
    context.ma20 = ta.SMA(np.asarray(context.close_array), 20)[:-1]
    
    # 开仓判断(仅新K线产生时执行,避免多次开仓)
    if len(context.ma5) >= 2 and len(context.ma20) >= 2:
        # 金叉开多
        if context.ma5[-2] <= context.ma20[-2] and context.ma5[-1] > context.ma20[-1] and context.position == 0:
            buy_open(1, context.base_instrument_id)
            context.position = 1

3.效果验证

通过on_bar_run绑定后,on_bar函数仅在每根 K 线收线时执行一次,无论该 K 线期间有多少 tick 数据,开仓逻辑都只触发一次,彻底解决 “同一根 K 线多次开仓” 问题。回测时可通过日志验证:在on_bar函数中添加put_log(f"新K线产生,执行开仓判断", level="INFO"),查看日志是否与 K 线数量一致。

注意:

若策略需要 “实时平仓”(如止损逻辑),可将平仓代码直接写在on_tick函数中,保留实时性;开仓逻辑仍放在on_bar中,确保按 K 线触发。

请登录后发表评论

    请登录后查看回复内容