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

PineScript中函数如何作用于数据?WPNR指标转换疑问

加权百分位近秩(WPNR)指标:PineScript转Python的核心疑问解析

我正尝试将以下PineScript的加权百分位近秩(WPNR)指标转换为Python,但无法理解函数如何作用于src。wpnr函数返回单个值,我认为这是每根K线的指标值,但为何每次传入相同的src却能返回不同值?

//@version=4
study('Weighted percentile nearest rank', 'WPNR', true, resolution='', resolution_gaps=true)
//by gorx1 & wallneradam

multisort(base_array, second_array, reverse) => //[
    n           = array.size(base_array)
    index_array = array.new_int(n)
    
    if n > 0
        for i = 0 to n - 1
            array.set(index_array, i, i)
        
        n -= 1
        
        for i = 0 to n > 0 ? n - 1 : na
            for j = 0 to n - i - 1
                t  = array.get(base_array, j) 
                t1 = array.get(base_array, j + 1) 
                    
                if (reverse ? t < t1 : t > t1)
                    array.set(base_array, j, t1)
                    array.set(base_array, j + 1, t)
                    
                    _t = array.get(second_array, j)
                    array.set(second_array, j, array.get(second_array, j + 1))
                    array.set(second_array, j + 1, _t)
                    
                    _ti = array.get(index_array, j)
                    array.set(index_array, j, array.get(index_array, j + 1))
                    array.set(index_array, j + 1, _ti)
    
    index_array //]

wpnr(src, len, n) => //[
    data    = array.new_float()
    weights = array.new_float()
    
    for i = 0 to len - 1
        array.push(data   , src[i] )
        array.push(weights, len - i) //the actual linear weights
        // array.push(weights, 1      ) //unit weights, if u wanna do a raincheck
    
    multisort(data, weights, false)
    
    sum         = 0.0
    weights_cum = array.new_float()
    
    for i = 0 to len - 1
        sum := sum + array.get(weights, i)
        array.push(weights_cum, sum)
    
    wpnr  = 0.0
    thres = array.sum(weights) / 100 * n

    for i = 0 to len - 1
        if array.get(weights_cum, i) >= thres
            wpnr := array.get(data, i)
            break
    
    wpnr //]

src = input(close, 'Source')
len = input(50   , 'Length')
n   = input(50   , '%'     )

out = wpnr(src, len, n)

plot(out, 'WPNR', color.rgb(255, 255, 255))

核心原因:PineScript的src是动态序列变量

  • 在PineScript中,src(比如示例里的close)不是固定不变的数组,而是随K线推进的滚动序列。每生成一根新K线,src会自动更新为包含最新len周期内的数据,最旧的周期数据会被挤出窗口。
  • 调用wpnr(src, len, n)时,src[i]取的是当前K线往前数第i根的数据源值:src[0]是当前K线的收盘价,src[1]是前一根K线的收盘价,直到src[len-1]是往前第len-1根K线的收盘价。每根K线计算时,这个滚动窗口的内容都不同,所以wpnr的返回值自然会变化。

wpnr函数执行逻辑拆解

  1. 构建加权数据窗口
    • 循环0到len-1,将当前滚动窗口内的src值存入data数组,同时生成线性权重:越新的K线权重越高(当前K线权重为len,最旧的为1)。
  2. 双数组同步排序
    • 调用multisort对data数组进行升序排序,同时同步调整weights数组的顺序,确保每个数据值对应正确的权重。
  3. 计算累计权重
    • 遍历排序后的weights数组,生成累计权重数组weights_cum,记录到每个位置为止的总权重。
  4. 定位百分位对应值
    • 计算阈值thres = 总权重 * n%,找到第一个累计权重≥阈值的data值,该值即为当前K线的WPNR结果。

Python转换实现示例

def multisort(base_array, second_array, reverse):
    n = len(base_array)
    index_array = list(range(n))
    
    if n > 0:
        n -= 1
        # 冒泡排序,同步调整三个数组
        for i in range(n if n > 0 else 0):
            for j in range(n - i):
                t = base_array[j]
                t1 = base_array[j + 1]
                # 根据reverse参数判断交换条件
                if (reverse and t < t1) or (not reverse and t > t1):
                    # 交换base数组元素
                    base_array[j], base_array[j+1] = base_array[j+1], base_array[j]
                    # 交换权重数组元素
                    second_array[j], second_array[j+1] = second_array[j+1], second_array[j]
                    # 交换索引数组元素
                    index_array[j], index_array[j+1] = index_array[j+1], index_array[j]
    return index_array

def wpnr(src_window, n_percent):
    len_window = len(src_window)
    data = src_window.copy()
    # 生成线性权重:越新的数据权重越高
    weights = [len_window - i for i in range(len_window)]
    
    # 对数据和权重同步排序
    multisort(data, weights, reverse=False)
    
    # 计算累计权重
    weights_cum = []
    total_weight = 0.0
    for w in weights:
        total_weight += w
        weights_cum.append(total_weight)
    
    # 计算百分位阈值
    threshold = total_weight * (n_percent / 100)
    wpnr_value = 0.0
    # 找到第一个累计权重≥阈值的数据值
    for i in range(len_window):
        if weights_cum[i] >= threshold:
            wpnr_value = data[i]
            break
    return wpnr_value

# 使用示例:假设你有一个收盘价序列close_prices(列表格式)
length = 50
percent = 50
wpnr_results = []

# 滚动计算每根K线的WPNR值
for i in range(length - 1, len(close_prices)):
    # 截取当前K线往前length个数据的窗口
    current_window = close_prices[i - length + 1 : i + 1]
    current_wpnr = wpnr(current_window, percent)
    wpnr_results.append(current_wpnr)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 01:10:12