mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-29 18:17:43 +00:00
83 lines
3.6 KiB
Plaintext
83 lines
3.6 KiB
Plaintext
// Licensed under the Apache License, Version 2.0
|
|
// © mihakralj
|
|
//@version=6
|
|
indicator("Jarque-Bera Test (JB)", "JB", overlay=false, precision=4)
|
|
|
|
// Helper function to get a window of series data into an array
|
|
_get_window_array(series float source, simple int length) =>
|
|
float[] arr = array.new_float(length)
|
|
for i = 0 to length - 1
|
|
array.set(arr, i, source[length - 1 - i]) // Oldest to newest
|
|
arr
|
|
|
|
// Helper function to calculate the k-th central moment
|
|
// m_k = sum((x_i - mean)^k) / n
|
|
_central_moment(float[] arr, int moment_order, float mean_val) =>
|
|
n = array.size(arr)
|
|
if n == 0
|
|
float(na)
|
|
else
|
|
sum_pow_diff = 0.0
|
|
for i = 0 to n - 1
|
|
sum_pow_diff += math.pow(array.get(arr, i) - mean_val, moment_order)
|
|
sum_pow_diff / n
|
|
|
|
//@function Calculates the Jarque-Bera statistic.
|
|
//@param source series float The input series.
|
|
//@param length simple int The lookback period (sample size). Min 10.
|
|
//@returns series float The Jarque-Bera statistic. Higher values suggest deviation from normality.
|
|
jb_stat(series float source, simple int length) => // Renamed function for clarity jb_stat -> jb
|
|
if length < 10 // Need sufficient sample size
|
|
float(na)
|
|
else
|
|
float[] window_arr = _get_window_array(source, length)
|
|
|
|
float mean_val = array.avg(window_arr) // Pine Script built-in array average
|
|
|
|
if na(mean_val)
|
|
float(na)
|
|
else
|
|
// Calculate variance (2nd central moment)
|
|
float m2 = _central_moment(window_arr, 2, mean_val)
|
|
|
|
if na(m2) or m2 < 1e-10 // Avoid division by zero or near-zero std dev
|
|
float(na) // Or 0 if data is truly constant, but JB is ill-defined
|
|
else
|
|
float stddev_val = math.sqrt(m2)
|
|
|
|
// Calculate 3rd central moment for skewness
|
|
float m3 = _central_moment(window_arr, 3, mean_val)
|
|
float s = m3 / math.pow(stddev_val, 3) // Skewness
|
|
|
|
// Calculate 4th central moment for kurtosis
|
|
float m4 = _central_moment(window_arr, 4, mean_val)
|
|
float k_raw = m4 / math.pow(stddev_val, 4) // Raw Kurtosis
|
|
float ek = k_raw - 3.0 // Excess Kurtosis
|
|
|
|
if na(s) or na(ek)
|
|
float(na)
|
|
else
|
|
// Jarque-Bera statistic formula: JB = (n/6) * (S^2 + (EK^2)/4)
|
|
float jb_value_calc = (length / 6.0) * (s * s + (ek * ek) / 4.0) // Renamed internal variable
|
|
jb_value_calc
|
|
|
|
// Inputs
|
|
i_source = input.source(close, title="Source")
|
|
i_length = input.int(20, title="Lookback Period (Sample Size)", minval=10, maxval=200, tooltip="Number of bars for calculation. Min 10. Max 200 due to array processing. Higher values provide more stable estimates but lag more.")
|
|
|
|
// Calculation
|
|
jb_value = jb_stat(i_source, i_length) // Call renamed function
|
|
|
|
// Plot
|
|
plot(jb_value, "Jarque-Bera Statistic", color=color.teal, linewidth=2)
|
|
|
|
// Critical values for Chi-squared distribution with 2 degrees of freedom (approximate):
|
|
// Significance Level | Critical Value
|
|
// 10% (0.10) | 4.605
|
|
// 5% (0.05) | 5.991
|
|
// 1% (0.01) | 9.210
|
|
// These lines can help interpret the JB statistic. If JB > critical value, reject null hypothesis of normality.
|
|
hline(4.605, "Critical Value (10%)", color.gray, linestyle=hline.style_dotted, linewidth=1)
|
|
hline(5.991, "Critical Value (5%)", color.orange, linestyle=hline.style_dashed, linewidth=1)
|
|
hline(9.210, "Critical Value (1%)", color.red, linestyle=hline.style_solid, linewidth=1)
|