Files

55 lines
2.2 KiB
Plaintext

// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Quantile (QUANTILE)", shorttitle="QUANTILE", overlay=true, precision=8)
//@function Calculates the quantile of a series over a lookback period using linear interpolation.
//@param src {series float} The source series to calculate the quantile from.
//@param len {simple int} The lookback period. Must be greater than 0.
//@param q_level {simple float} The quantile level to calculate (between 0.0 and 1.0).
//@returns {series float} The calculated quantile value, or na if insufficient data.
quantile(series float src, simple int len, simple float q_level) =>
if len <= 0
runtime.error("Period must be greater than 0.")
if q_level < 0.0 or q_level > 1.0
runtime.error("Quantile Level must be between 0.0 and 1.0.")
var float[] values_arr = array.new_float(0)
array.clear(values_arr)
for i = 0 to len - 1
if not na(src[i])
array.push(values_arr, src[i])
int n_valid = array.size(values_arr)
if n_valid == 0
na
else if n_valid == 1
array.get(values_arr, 0)
else
array.sort(values_arr)
if q_level == 0.0
array.min(values_arr)
else if q_level == 1.0
array.max(values_arr)
else
float rank = q_level * (n_valid - 1)
int k_floor = int(math.floor(rank))
int k_ceil = int(math.ceil(rank))
if k_floor == k_ceil
array.get(values_arr, k_floor)
else
float val_floor = array.get(values_arr, k_floor)
float val_ceil = array.get(values_arr, k_ceil)
val_floor + (rank - k_floor) * (val_ceil - val_floor)
// ---------- Main loop ----------
// Inputs
i_source = input.source(close, title="Source")
i_length = input.int(14, title="Period", minval=1)
i_quantile_level = input.float(0.25, title="Quantile Level (0.0-1.0)", minval=0.0, maxval=1.0, step=0.01)
// Calculate Quantile
quantile_value = quantile(i_source, i_length, i_quantile_level)
// Plot
plot(quantile_value, title="Quantile", color=color.new(color.yellow, 0, color=color.yellow, linewidth=2), linewidth=2)