Advertisement
NKactive

Untitled

Sep 16th, 2024
33
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.32 KB | None | 0 0
  1. //@version=5
  2. indicator("πŸ‘Ί π•Ύπ–•π–Šπ–ˆπ–Žπ–†π–‘π–Žπ–˜π–™ π•Ύπ–™π–†π–™π–Žπ–˜π–™π–Žπ–ˆπ–†π–‘ π•Ύπ–šπ–Žπ–™π–Š πŸ‘Ί", overlay=false)
  3.  
  4. // Input lengths
  5. ADF_LEN = input.int(20, title="ADF Length")
  6. PP_LEN = input.int(2, title="PP Length")
  7. HURST_LEN = input.int(30, title="Hurst Exponent Length", minval=1)
  8. KPSS_LEN = input.int(75, title="KPSS Length")
  9.  
  10. var table result_table = table.new(position.middle_right, 4, 8, border_width=1, border_color=color.gray, frame_color=color.gray)
  11.  
  12. // ADF Test
  13. src = input.source(title='Source', defval=close)
  14. lookback = input.int(title='Length', defval=30, minval = 2, tooltip = 'The test is applied in a moving window. Length defines the number of points in the sample.')
  15. nLag = input.int(title='Maximum lag', defval=0, minval = 0, tooltip = 'Maximum lag which is included in test. Generally, lags allow taking into account serial correlation of price changes.')
  16. conf = input.string(title='Confidence Level', defval="90%", options = ['90%', '95%', '99%'], tooltip = 'Defines at which confidence level the critical value of the ADF test statistic is calculated. If the test statistic is below the critical value, the time series sample is concluded to be mean-reverting.')
  17.  
  18. // Matrix
  19. matrix_get(A, i, j, nrows) =>
  20. array.get(A, i + nrows * j)
  21.  
  22. matrix_set(A, value, i, j, nrows) =>
  23. array.set(A, i + nrows * j, value)
  24. A
  25.  
  26. transpose(A, nrows, ncolumns) =>
  27. float[] AT = array.new_float(nrows * ncolumns, 0)
  28. for i = 0 to nrows - 1
  29. for j = 0 to ncolumns - 1
  30. matrix_set(AT, matrix_get(A, i, j, nrows), j, i, ncolumns)
  31. AT
  32.  
  33. multiply(A, B, nrowsA, ncolumnsA, ncolumnsB) =>
  34. float[] C = array.new_float(nrowsA * ncolumnsB, 0)
  35. int nrowsB = ncolumnsA
  36. float elementC = 0.0
  37. for i = 0 to nrowsA - 1
  38. for j = 0 to ncolumnsB - 1
  39. elementC := 0
  40. for k = 0 to ncolumnsA - 1
  41. elementC += matrix_get(A, i, k, nrowsA) * matrix_get(B, k, j, nrowsB)
  42. matrix_set(C, elementC, i, j, nrowsA)
  43. C
  44.  
  45. vnorm(X) =>
  46. int n = array.size(X)
  47. float norm = 0.0
  48. for i = 0 to n - 1
  49. norm += math.pow(array.get(X, i), 2)
  50. math.sqrt(norm)
  51.  
  52. qr_diag(A, nrows, ncolumns) =>
  53. float[] Q = array.new_float(nrows * ncolumns, 0)
  54. float[] R = array.new_float(ncolumns * ncolumns, 0)
  55. float[] a = array.new_float(nrows, 0)
  56. float[] q = array.new_float(nrows, 0)
  57. float r = 0.0
  58. float aux = 0.0
  59. for i = 0 to nrows - 1
  60. array.set(a, i, matrix_get(A, i, 0, nrows))
  61. r := vnorm(a)
  62. matrix_set(R, r, 0, 0, ncolumns)
  63. for i = 0 to nrows - 1
  64. matrix_set(Q, array.get(a, i) / r, i, 0, nrows)
  65. if ncolumns != 1
  66. for k = 1 to ncolumns - 1
  67. for i = 0 to nrows - 1
  68. array.set(a, i, matrix_get(A, i, k, nrows))
  69. for j = 0 to k - 1
  70. r := 0
  71. for i = 0 to nrows - 1
  72. r += matrix_get(Q, i, j, nrows) * array.get(a, i)
  73. matrix_set(R, r, j, k, ncolumns)
  74. for i = 0 to nrows - 1
  75. aux := array.get(a, i) - r * matrix_get(Q, i, j, nrows)
  76. array.set(a, i, aux)
  77. r := vnorm(a)
  78. matrix_set(R, r, k, k, ncolumns)
  79. for i = 0 to nrows - 1
  80. matrix_set(Q, array.get(a, i) / r, i, k, nrows)
  81. [Q, R]
  82.  
  83. pinv(A, nrows, ncolumns) =>
  84. [Q, R] = qr_diag(A, nrows, ncolumns)
  85. float[] QT = transpose(Q, nrows, ncolumns)
  86. var Rinv = array.new_float(ncolumns * ncolumns, 0)
  87. float r = 0.0
  88. matrix_set(Rinv, 1 / matrix_get(R, 0, 0, ncolumns), 0, 0, ncolumns)
  89. if ncolumns != 1
  90. for j = 1 to ncolumns - 1
  91. for i = 0 to j - 1
  92. r := 0.0
  93. for k = i to j - 1
  94. r += matrix_get(Rinv, i, k, ncolumns) * matrix_get(R, k, j, ncolumns)
  95. matrix_set(Rinv, r, i, j, ncolumns)
  96. for k = 0 to j - 1
  97. matrix_set(Rinv, -matrix_get(Rinv, k, j, ncolumns) / matrix_get(R, j, j, ncolumns), k, j, ncolumns)
  98. matrix_set(Rinv, 1 / matrix_get(R, j, j, ncolumns), j, j, ncolumns)
  99. float[] Ainv = multiply(Rinv, QT, ncolumns, ncolumns, nrows)
  100. Ainv
  101.  
  102. adftest(a, nLag, conf) =>
  103. if nLag >= array.size(a)/2 - 2
  104. runtime.error("ADF: Maximum lag must be less than (Length/2 - 2)")
  105. int nobs = array.size(a)-nLag-1
  106. float[] y = array.new_float(na)
  107. float[] x = array.new_float(na)
  108. float[] x0 = array.new_float(na)
  109. for i = 0 to nobs-1
  110. array.push( y, array.get(a,i)-array.get(a,i+1))
  111. array.push( x, array.get(a,i+1))
  112. array.push(x0, 1.0)
  113. float[] X = array.copy(x)
  114. int M = 2
  115. X := array.concat(X, x0)
  116. if nLag > 0
  117. for n = 1 to nLag
  118. float[] xl = array.new_float(na)
  119. for i = 0 to nobs-1
  120. array.push(xl, array.get(a,i+n)-array.get(a,i+n+1))
  121. X := array.concat(X, xl)
  122. M += 1
  123. float[] c = pinv(X, nobs, M)
  124. float[] coeff = multiply(c, y, M, nobs, 1)
  125. float[] Yhat = multiply(X,coeff,nobs,M,1)
  126. float meanX = array.avg(x)
  127. float sum1 = 0.0
  128. float sum2 = 0.0
  129. for i = 0 to nobs-1
  130. sum1 += math.pow(array.get(y,i) - array.get(Yhat,i), 2)/(nobs-M)
  131. sum2 += math.pow(array.get(x,i) - meanX, 2)
  132. float SE = math.sqrt(sum1/sum2)
  133. float adf = array.get(coeff,0) /SE
  134. float crit = switch
  135. conf == "90%" => -2.56677 - 1.5384/nobs - 2.809/nobs/nobs
  136. conf == "95%" => -2.86154 - 2.8903/nobs - 4.234/nobs/nobs - 40.040/nobs/nobs/nobs
  137. conf == "99%" => -3.43035 - 6.5393/nobs - 16.786/nobs/nobs - 79.433/nobs/nobs/nobs
  138. [adf, crit, nobs]
  139.  
  140. // Load data from a moving window into an array
  141. float[] a = array.new_float(na)
  142. for i = 0 to lookback-1
  143. array.push(a,src[i])
  144.  
  145. // Perform the ADF test
  146. [tauADF, crit, nobs] = adftest(a, nLag, conf)
  147.  
  148. //plot(tauADF, title="ADF Test Statistic", color=color.red)
  149. //plot(crit, title="ADF Critical Value", color=color.green)
  150.  
  151. // Phillips-Perron (PP) Test
  152. logReturns(series) =>
  153. math.log(series / series[1])
  154.  
  155. price = close
  156. logReturnsSeries = logReturns(price)
  157. lookbackPeriod = PP_LEN
  158. meanLogReturns = ta.sma(logReturnsSeries, lookbackPeriod)
  159. stdLogReturns = ta.stdev(logReturnsSeries, lookbackPeriod)
  160. b = ta.correlation(logReturnsSeries, logReturnsSeries[1], lookbackPeriod) * (stdLogReturns / ta.stdev(logReturnsSeries[1], lookbackPeriod))
  161. residuals = logReturnsSeries - (meanLogReturns + b * logReturnsSeries[1])
  162. pp_z = ((b - 1) / ta.stdev(residuals, lookbackPeriod)) /10 //Calming down stat, remove if reqd
  163. criticalValue = input.float(-70)
  164. //plot(pp_z, title="PP Test Statistic", color=color.blue)
  165. //hline(criticalValue, title="Critical Value", color=color.red)
  166.  
  167. // Hurst Exponent calculation
  168. N = HURST_LEN
  169. hurst_exponent(source, length) =>
  170. float result = na
  171. if not na(source[0])
  172. mean = ta.sma(source, length)
  173. cumulative_dev = array.new_float(length, 0.0)
  174. for i = 0 to (length - 1)
  175. if not na(source[i])
  176. array.set(cumulative_dev, i, source[i] - mean)
  177. cumulative_sum = 0.0
  178. Y = array.new_float(length, 0.0)
  179. for i = 0 to (length - 1)
  180. cumulative_sum += array.get(cumulative_dev, i)
  181. array.set(Y, i, cumulative_sum)
  182. R = array.max(Y) - array.min(Y)
  183. S = ta.stdev(source, length)
  184. result := math.log(R / S) / math.log(length)
  185. result
  186. close_prices = request.security(syminfo.tickerid, 'D', close)
  187. H = hurst_exponent(close_prices, N)
  188.  
  189. // KPSS Test
  190. length = KPSS_LEN
  191. f_linreg(src, length) =>
  192. linreg_val = ta.linreg(src, length, 0)
  193. linreg_val
  194.  
  195. linreg_values = f_linreg(close, length)
  196. KPSSresiduals = close - linreg_values
  197. partial_sums = 0.0
  198. partial_sum_squared = 0.0
  199. for i = 0 to length - 1
  200. partial_sums += nz(KPSSresiduals[i])
  201. partial_sum_squared += partial_sums * partial_sums
  202. lags = math.floor(math.sqrt(length))
  203. sum_residuals = 0.0
  204. for i = 0 to length - 1
  205. sum_residuals += nz(KPSSresiduals[i]) * nz(KPSSresiduals[i])
  206. for lag = 1 to lags
  207. weight = 1.0 - lag / (lags + 1.0)
  208. lag_sum = 0.0
  209. for i = lag to length - 1
  210. lag_sum += nz(KPSSresiduals[i]) * nz(KPSSresiduals[i - lag])
  211. sum_residuals += 2 * weight * lag_sum
  212. long_run_variance = sum_residuals / length
  213. kpss_stat = partial_sum_squared / (length * length * long_run_variance)
  214. critical_value_kpss = input.float(0.5, step = 0.01)
  215. //plot(kpss_stat, title="KPSS Test", color=color.orange)
  216.  
  217.  
  218. //Clamping function to keep the value within the specified range
  219. clamp(value, min_value, max_value) =>
  220. math.min(math.max(value, min_value), max_value)
  221.  
  222. // Mapping functions
  223. normalize_statistic(value, min_value, max_value) =>
  224. 2 * ((value - min_value) / (max_value - min_value)) - 1
  225.  
  226. // Normalize ADF and PP scores using their respective critical values
  227. tauADF_clamped = clamp(tauADF, -1, 1) // Adjust the range based on your data
  228. normalized_tauADF = normalize_statistic(tauADF_clamped, -1, 1) // Adjust the range based on your data
  229. pp_z_clamped = clamp(pp_z, -1, 1) // Adjust the range based on your data
  230. normalized_pp_z = normalize_statistic(pp_z_clamped, -1, 1) // Adjust the range based on your data
  231. H_clamped = clamp(H, -1, 1) // Adjust the range based on your data
  232. normalized_H = 2 * (math.abs(H_clamped - 0.5) / 0.5) - 1
  233. kpss_stat_clamped = clamp(kpss_stat, -1, 1) // Adjust the range based on your data
  234. normalized_kpss_stat = normalize_statistic(kpss_stat_clamped, -1, 1) // Adjust the range based on your data
  235.  
  236. // Plotting
  237. //plot(tauADF, title="ADF Test Statistic", color=color.red)
  238. //plot(crit, title="ADF Critical Value", color=color.green)
  239. //plot(pp_z, title="Phillips-Perron Test Z-Score", color=color.blue)
  240. //plot(H, title="Hurst Exponent", color=color.purple)
  241. //plot(kpss_stat, title="KPSS Test", color=color.orange)
  242.  
  243. // Function to round value to specified decimal places
  244. roundTo(value, decimals) =>
  245. factor = math.pow(10, decimals)
  246. math.round(value * factor) / factor
  247.  
  248. // Update table with ADF, PP, Hurst, and KPSS results
  249. if bar_index == 0
  250. // Title row
  251. table.cell(result_table, 0, 0, "π•Ύπ–•π–Šπ–ˆπ–Žπ–†π–‘π–Žπ–˜π–™", bgcolor=color.gray, text_color=color.white)
  252. table.cell(result_table, 1, 0, "π•Ύπ–™π–†π–™π–Žπ–˜π–™π–Žπ–ˆπ–†π–‘", bgcolor=color.gray, text_color=color.white)
  253. table.cell(result_table, 2, 0, "π•Ύπ–šπ–Žπ–™π–Š", bgcolor=color.gray, text_color=color.white)
  254.  
  255. // Header row
  256. table.cell(result_table, 0, 1, "Test", bgcolor=color.gray)
  257. table.cell(result_table, 1, 1, "Value", bgcolor=color.gray)
  258. table.cell(result_table, 2, 1, "Normalized Value", bgcolor=color.gray)
  259.  
  260. // Data labels
  261. table.cell(result_table, 0, 2, "ADF Statistic", bgcolor=color.white)
  262. table.cell(result_table, 0, 3, "PP Statistic", bgcolor=color.white)
  263. table.cell(result_table, 0, 4, "Hurst Exponent", bgcolor=color.white)
  264. table.cell(result_table, 0, 5, "KPSS Statistic", bgcolor=color.white)
  265.  
  266. table.cell(result_table, 1, 2, str.tostring(roundTo(tauADF, 4)), bgcolor=color.white)
  267. table.cell(result_table, 1, 3, str.tostring(roundTo(pp_z, 4)), bgcolor=color.white)
  268. table.cell(result_table, 1, 4, str.tostring(roundTo(H, 4)), bgcolor=color.white)
  269. table.cell(result_table, 1, 5, str.tostring(roundTo(kpss_stat, 4)), bgcolor=color.white)
  270. table.cell(result_table, 2, 2, str.tostring(roundTo(normalized_tauADF, 4)), bgcolor=color.white)
  271. table.cell(result_table, 2, 3, str.tostring(roundTo(normalized_pp_z, 4)), bgcolor=color.white)
  272. table.cell(result_table, 2, 4, str.tostring(roundTo(normalized_H, 4)), bgcolor=color.white)
  273. table.cell(result_table, 2, 5, str.tostring(roundTo(normalized_kpss_stat, 4)), bgcolor=color.white)
  274.  
  275. // Calculate average of normalized values
  276. average_normalized = (normalized_tauADF + normalized_pp_z + normalized_H + normalized_kpss_stat) / 4
  277.  
  278. // Add average row
  279. table.cell(result_table, 0, 6, "Average Normalized Value", bgcolor=color.white)
  280. table.cell(result_table, 1, 6, "πŸ‘Ί", bgcolor=color.white)
  281. table.cell(result_table, 2, 6, str.tostring(roundTo(average_normalized, 4)), bgcolor=color.white)
  282.  
  283. // Add trend interpretation row
  284. trend_interpretation = average_normalized >= 0 ? "Trend Following" : "Mean Reverting"
  285. table.cell(result_table, 0, 7, "Trend Interpretation", bgcolor=color.white)
  286. table.cell(result_table, 1, 7, "πŸ‘Ί", bgcolor=color.white)
  287. table.cell(result_table, 2, 7, trend_interpretation, bgcolor=color.white)
  288.  
  289. // Plotting
  290. plot(normalized_tauADF, title="Normalized ADF Test Statistic", color=color.red)
  291. plot(normalized_pp_z, title="Normalized PP Test Statistic", color=color.blue)
  292. plot(normalized_H, title="Normalized Hurst Exponent", color=color.purple)
  293. plot(normalized_kpss_stat, title="Normalized KPSS Test", color=color.orange)
  294.  
  295. // NK's Plot
  296. colorState = average_normalized >= 0 ? color.lime : color.fuchsia
  297. plot(average_normalized, title="Average",color=colorState)
  298.  
  299. //There is neither happiness nor unhappiness in this world; there is only the comparison of one state with another. Only a man who has felt ultimate despair is capable of feeling ultimate bliss. It is necessary to have wished for death in order to know how good it is to live.....the sum of all human wisdom will be contained in these two words: Wait and Hope.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement