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

求盈亏跨越指定百分比时的Bar Index及代码问题排查

Pine Script v5 交易盈亏达标K线索引捕获问题修正

问题描述

需要捕获盈利/亏损(绝对值)跨越指定百分比(示例为2%)时的K线索引,现有代码存在两个问题:

  • 出现负K线索引:未满足条件的开仓交易错误沿用了之前交易的K线索引
  • 开仓同K线达标时无法捕获该K线索引

尝试过strategy.opentrades.max_runup和max_drawdown未解决,原代码如下:

//@version=5
strategy("Testing", process_orders_on_close=false)

pine_dev(source, length) =>
    mean = ta.sma(source, length)
    sum = 0.0
    for i = 0 to length - 1
        val = source[i]
        sum := sum + math.abs(val - mean)
    dev = sum/length

indicator = pine_dev(close,9)

percentile = (ta.percentrank(indicator,9))

if percentile <= 25
    strategy.entry("Enter Trade",strategy.long)

if percentile == 100
    strategy.close("Enter Trade",comment="Exit Trade")


var number_of_trades = 0
var max_move = 2.0
var bar_index_max_move = 0
var tradeMax1 = 0.0
var array<int> moveBars = array.new_int()
maxArrb = array.new_int()

for i = 0 to strategy.opentrades - 1
    cost = strategy.opentrades.entry_price(i)
    size = strategy.opentrades.size(i)
    profit = strategy.opentrades.profit(i)
    float tradeMax = math.abs(profit/(cost*size)*100)
    tradeMax1 := tradeMax

if ta.change(tradeMax1 >= max_move) and strategy.opentrades > 0
    max_move := tradeMax1
    bar_index_max_move := bar_index

if strategy.closedtrades > number_of_trades
    number_of_trades := number_of_trades + 1
    if max_move != 0
        array.push(moveBars,bar_index_max_move)
        // Reset values
        max_move := 2.0

for [j, bar] in moveBars
    int entryBar = strategy.closedtrades.entry_bar_index(j) 
    int barsToMaxMove = bar - entryBar
    array.push(maxArrb, barsToMaxMove)

//Label and plot to check if the output of the bar index is correct
plot(array.size(maxArrb))
maxArrb_string = str.tostring(maxArrb)
debug = label.new(x = bar_index, y = close, style = label.style_label_left, text = maxArrb_string)
label.delete(debug[1])

修正后的代码

//@version=5
strategy("Testing Fixed", process_orders_on_close=false)

// 自定义指标计算逻辑保持不变
pine_dev(source, length) =>
    mean = ta.sma(source, length)
    sum = 0.0
    for i = 0 to length - 1
        val = source[i]
        sum := sum + math.abs(val - mean)
    dev = sum/length

indicator = pine_dev(close, 9)
percentile = ta.percentrank(indicator, 9)

// 交易信号逻辑保持不变
if percentile <= 25
    strategy.entry("Enter Trade", strategy.long)

if percentile == 100
    strategy.close("Enter Trade", comment="Exit Trade")

// -------------------------- 核心修正部分 --------------------------
var float target_pct = 2.0  // 目标盈亏百分比
var array<int> trade_entry_bars = array.new_int()  // 存储每笔交易的开仓K线索引
var array<int> target_hit_bars = array.new_int()    // 存储每笔交易首次达标K线索引
var array<bool> target_hit_flag = array.new_bool()  // 标记交易是否已达标

// 处理开仓:新交易初始化追踪数据
if strategy.opentrades > array.size(trade_entry_bars)
    current_entry_bar = strategy.opentrades.entry_bar_index(strategy.opentrades - 1)
    array.push(trade_entry_bars, current_entry_bar)
    array.push(target_hit_bars, na)
    array.push(target_hit_flag, false)

// 遍历所有持仓交易,检查是否达标
for i = 0 to strategy.opentrades - 1
    if not array.get(target_hit_flag, i)  // 仅处理未达标交易
        entry_price = strategy.opentrades.entry_price(i)
        current_pnl_pct = math.abs((close - entry_price) / entry_price * 100)
        
        // 达标判定(包含开仓同K线情况)
        if current_pnl_pct >= target_pct
            array.set(target_hit_bars, i, bar_index)
            array.set(target_hit_flag, i, true)

// 处理平仓:将达标数据归档,并清理已结束交易的追踪数据
var array<int> final_target_bars = array.new_int()  // 最终存储所有交易的达标K线索引
var array<int> bars_to_target = array.new_int()     // 存储开仓到达标所需K线数

if strategy.closedtrades > array.size(final_target_bars)
    closed_trade_idx = strategy.closedtrades - 1
    entry_bar = strategy.closedtrades.entry_bar_index(closed_trade_idx)
    
    // 找到对应交易的达标K线索引
    trade_pos = array.indexof(trade_entry_bars, entry_bar)
    if trade_pos != -1
        hit_bar = array.get(target_hit_bars, trade_pos)
        // 若开仓到平仓都未达标,可根据需求处理(这里设为na)
        final_hit_bar = na(hit_bar) ? na : hit_bar
        array.push(final_target_bars, final_hit_bar)
        
        // 计算开仓到达标K线数
        if not na(final_hit_bar)
            array.push(bars_to_target, final_hit_bar - entry_bar)
        
        // 清理已结束交易的追踪数据
        array.remove(trade_entry_bars, trade_pos)
        array.remove(target_hit_bars, trade_pos)
        array.remove(target_hit_flag, trade_pos)

// 调试可视化:绘制达标交易数数组大小,显示数组内容
plot(array.size(bars_to_target), title="达标交易数")
bars_str = str.tostring(bars_to_target)
debug_label = label.new(bar_index, close, text=bars_str, style=label.style_label_left)
label.delete(debug_label[1])

修正说明

  1. 避免跨交易数据污染:为每笔交易单独维护target_hit_flag、target_hit_bars等追踪变量,不再使用全局变量共享状态,彻底解决负索引问题。
  2. 捕获开仓同K线达标场景:在开仓后立即检查当前K线的盈亏百分比,一旦达标就记录当前K线索引,无需等待下一根K线。
  3. 交易生命周期管理:开仓时初始化追踪数据,平仓时归档结果并清理对应数据,确保追踪数组仅保留活跃交易的信息。
  4. 灵活的未达标处理:若交易全程未达到目标百分比,可自行调整final_hit_bar的赋值逻辑(当前设为na)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 17:25:19