You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pine Script Bar Replay重绘,回测与回放结果不一致问题咨询

问题描述

已采取多项防重绘措施(request.security()使用[1]索引获取高时间框架已闭合K线、关闭calc_on_order_fills=true/calc_on_every_tick=true、启用lookahead_off),但运行Bar Replay时,回放完成后的交易记录与回测引擎图表显示结果不一致,存在过往交易重绘情况,无法确定实盘应信任哪一种结果。

策略逻辑:基于2小时高时间框架的high[1]/low[1]/close[1]计算趋势,当(close - 最低低)/(最高高 - 最低低) > 0.5时触发多单信号,反之触发空单信号,要求回测与Bar Replay结果完全一致。

问题原因
  1. 跨时间框架数据同步逻辑差异:回测引擎基于完整历史数据批量计算跨周期指标,而Bar Replay是模拟实时逐bar推进。即使使用high[1],默认的barmerge.gaps_on会让低时间框架K线在高时间框架未更新时重复使用旧的高时间框架数据,导致回测和回放时信号触发的时机判断出现偏差。
  2. 高低点计算的累积差异:ta.highest()/ta.lowest()在回测中是一次性计算完整周期的高低点,而Bar Replay中是逐bar累积计算,过程中临时高低点会变化,导致趋势信号在回放过程中出现临时波动,最终生成与回测不同的交易记录。
  3. 信号触发逻辑的无状态性:原代码中趋势信号每根低时间框架K线都会重新计算,未对高时间框架的信号稳定性做确认,导致回放时临时信号触发不必要的交易。
解决方案

核心思路是让所有跨周期计算都在高时间框架内完成,避免低时间框架的逐bar计算干扰,同时确保信号仅在高时间框架K线闭合后才更新,具体步骤:

  • 将高低点计算、趋势信号判断全部封装到request.security()的回调函数中,让计算逻辑完全在高时间框架层面执行。
  • 配置barmerge.gaps_off,确保低时间框架仅在高时间框架K线更新时获取新数据,避免重复使用旧数据导致的信号波动。
  • 添加信号稳定性确认,仅当趋势信号连续稳定时才触发交易,过滤临时波动。
修改后的策略代码
//@version=5
global_strategy_name = "Mobius_Useful_Candles2_Strat_Matts"
strategy(global_strategy_name, shorttitle=global_strategy_name, 
     overlay=true, 
     initial_capital=1000, 
     pyramiding=1, 
     precision=2,
     calc_on_order_fills=false, 
     calc_on_every_tick=false, 
     default_qty_type=strategy.fixed,
     default_qty_value=1, 
     currency=currency.NONE, 
     slippage=30, 
     commission_type=strategy.commission.cash_per_contract, 
     commission_value=0.01)

//=========================== INPUTS ===========================//
input_agg_period = input.timeframe(
     title = "Higher TimeFrame Aggregation Period", 
     defval = "120",
     group = 'Strategy')

input_trend_periods = input.int(
     title = "Trend Periods", 
     minval = 1, 
     defval = 358,
     group = 'Strategy')

//=========================== 跨周期计算封装到高时间框架内部 ===========================//
// 在高时间框架内完成高低点计算和趋势信号生成
trendSignal = request.security(syminfo.ticker, input_agg_period, ta.valuewhen(barstate.islast, 
    let hh = ta.highest(high, input_trend_periods),
        ll = ta.lowest(low, input_trend_periods),
        (close - ll) / (hh - ll) > 0.5 ? 1 : 0
, 1), barmerge.gaps_off, barmerge.lookahead_off)

// 信号确认:确保当前信号与前一根高时间框架信号一致,避免临时波动
confirmedTrendSignal = trendSignal == trendSignal[1]

// Update the bar colours for visual inspection
barcolor(confirmedTrendSignal and trendSignal == 1 ? color.rgb(0, 252, 0) : color.red)

// Define entry conditions
longCondition = confirmedTrendSignal and trendSignal == 1
shortCondition = confirmedTrendSignal and trendSignal == 0

// Check for currently held positions
bool longIsActive = strategy.position_size > 0
bool shortIsActive = strategy.position_size < 0

// Define exit conditions
bool validExitLongPosition = shortCondition and longIsActive
bool validExitShortPosition = longCondition and shortIsActive

// Enter/Exit trades
if longCondition
    strategy.entry("Enter Long", strategy.long, alert_message = "MOBIUS - Enter Long")
else if shortCondition
    strategy.entry("Enter Short", strategy.short, alert_message = "MOBIUS - Enter Short")

if validExitLongPosition or validExitShortPosition
    strategy.close_all("x", alert_message = global_strategy_name + " - Exit Position")
代码修改说明
  1. 跨周期计算封装:将ta.highest()/ta.lowest()和趋势信号判断全部放在request.security()的回调中,确保所有计算都在高时间框架完成,返回的是高时间框架K线闭合后的稳定信号。
  2. 数据同步配置:添加barmerge.gaps_off,低时间框架仅在高时间框架K线更新时获取新的趋势信号,避免重复使用旧数据。
  3. 信号确认:新增confirmedTrendSignal,确保当前趋势信号与前一根高时间框架信号一致,过滤临时波动导致的虚假信号。

内容的提问来源于stack exchange,提问作者windowshopr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 19:54:55