Advertisement
xmd79

The Next Pivot [Kioseff Trading]

Aug 31st, 2023
582
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 20.93 KB | None | 0 0
  1. // This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
  2. // © Kioseff Trading
  3.  
  4. //@version=5
  5. indicator("The Next Pivot [Kioseff Trading]", overlay=true, max_lines_count = 500, max_boxes_count = 500, max_labels_count = 500)
  6.  
  7.  
  8. import TradingView/ZigZag/6 as ZigZagLib
  9. import HeWhoMustNotBeNamed/arraymethods/1
  10. import RicardoSantos/MathOperator/2
  11.  
  12. historical = input.int(defval = 20, title = "Correlation Length", minval = 5, maxval = 100, group = "How Long Should The Correlating Sequences Be? (Bars Back)")
  13. forecastLen = input.int(defval = 50, minval = 15, maxval = 250, title = "Forecast Length", group = "How Long Should The Forecast Be?")
  14.  
  15. typec = input.string("Cosine Similarity", title = "Similarity Calculation", options =
  16. ["Spearmen", "Pearson", "Euclidean (Absolute Difference)", "Cosine Similarity", "Mean Squared Error", "Kendall"], group = "Similarity Method"), var t = time
  17. simtype = input.string(defval = "Price", title = "Looks For Similarities In", options = ["%Change", "Price"], group = "Similarity Method")
  18. tim = input.int(defval = 5000, minval = 500, step = 1000, title = "Bars Back To Search",
  19. group ="How Many Bars Back Should We Look To Find The Most Similar Sequence?")
  20.  
  21. zonly = input.bool(defval = true , title = "Show Projected Zig Zag" , group = "Aesthetics", inline = "Projected")
  22. ponly = input.bool(defval = true, title = "Show Projected Price Path", group = "Aesthetics", inline = "Projected")
  23. on = input.bool(defval = false, title = "", inline = "Lin", group = "Aesthetics")
  24. stdev = input.float(defval = 1, title = "Lin Reg σ", minval = 0, step = 0.1, inline = "Lin", group = "Aesthetics")
  25.  
  26. projcol = input.color(defval = #14D990, title = "Projected Zig Zag Color", inline = "1", group = "Aesthetics")
  27. forecastCol = input.color(defval = color.white , title = "Forecast Color  ", inline = "1", group = "Aesthetics")
  28.  
  29. var ret = array.new_float(), var mastertime = array.new_int(), result = matrix.new<float>(2, 1, -1e8), float [] recRet = na
  30.  
  31. method rankEstimate(array <float> id, iteration) =>
  32.  
  33. math.round((id.percentrank(iteration) / 100) * (historical - 1) + 1)
  34.  
  35. method effSlice(array<float> id, iteration) =>
  36.  
  37. id.slice(iteration, iteration + historical)
  38.  
  39. method update (matrix <float> id, float id2, i) =>
  40.  
  41. if id2.over_equal(id.get(0, 0))
  42.  
  43. id.set(0, 0, id2)
  44. id.set(1, 0, i)
  45.  
  46. method spearmen (matrix <float> id) =>
  47.  
  48.  
  49. denominator = (historical * (math.pow(historical, 2) - 1))
  50. estimate = array.new_int()
  51.  
  52. for i = 0 to recRet.size() - 1
  53. estimate.push(recRet.rankEstimate(i))
  54.  
  55. for i = 0 to ret.size() - historical * 2 - forecastLen
  56.  
  57. slice = ret.effSlice(i)
  58. d2 = array.new_float(historical)
  59.  
  60. for x = 0 to historical - 1
  61.  
  62. s = estimate.get(x)
  63. s1 = slice.rankEstimate(x)
  64. fin = math.pow(s - s1, 2)
  65. d2.set(x, fin)
  66.  
  67. r = 1 - (6 * d2.sum()) / denominator
  68.  
  69. id.update(i, r)
  70.  
  71. method pearson (matrix <float> id) =>
  72.  
  73. stdevA = recRet.stdev()
  74.  
  75. for i = 0 to ret.size() - historical * 2 - forecastLen
  76.  
  77. slice = ret.effSlice(i)
  78. p = slice.covariance(recRet) / (stdevA * slice.stdev())
  79.  
  80. id.update(p, i)
  81.  
  82. method euc (matrix <float> id) =>
  83.  
  84. for i = 0 to ret.size() - historical * 2 - forecastLen
  85.  
  86. slice = ret.effSlice(i)
  87. euc = array.new_float(historical)
  88.  
  89. for x = 0 to historical - 1
  90.  
  91. euc.set(x, math.pow(recRet.get(x) - slice.get(x), 2))
  92.  
  93. inv = 1 / (1 + math.sqrt(euc.sum()))
  94.  
  95. id.update(inv, i)
  96.  
  97.  
  98. method cosine(matrix <float> id) =>
  99.  
  100. nA = 0.
  101.  
  102. for i = 0 to recRet.size() - 1
  103. nA += math.pow(recRet.get(i), 2)
  104.  
  105. nA := math.sqrt(nA)
  106.  
  107. for i = 0 to ret.size() - historical * 2 - forecastLen
  108.  
  109. slice = ret.effSlice(i)
  110. prod = 0., nB = 0.
  111.  
  112. for x = 0 to historical - 1
  113.  
  114. prod += recRet.get(x) * slice.get(x)
  115. nB += math.pow(slice.get(x), 2)
  116.  
  117. cos = prod / (nA * math.sqrt(nB))
  118. id.update(cos, i)
  119.  
  120.  
  121. method mse (matrix <float> id) =>
  122.  
  123. for i = 0 to ret.size() - historical * 2 - forecastLen
  124.  
  125. slice = ret.effSlice(i)
  126. mse = array.new_float(historical)
  127.  
  128. for x = 0 to historical - 1
  129. mse.set(x, math.pow(slice.get(x) - recRet.get(x), 2))
  130.  
  131. mseC = 1 / (1 + mse.sum() / historical)
  132.  
  133. id.update(mseC, i)
  134.  
  135.  
  136. method kendall (matrix <float> id) =>
  137.  
  138. for i = 0 to ret.size() - historical * 2 - forecastLen
  139.  
  140. slice = ret.effSlice(i)
  141. valMat = matrix.new<float>(4, math.ceil(slice.size() * (slice.size() - 1) / 2), 0)
  142. iteration = 0
  143.  
  144. for x = 0 to slice.size() - 1
  145. for y = x + 1 to historical - 1
  146. if y > historical - 1
  147. break
  148.  
  149. diff1 = recRet.get(y) - recRet.get(x)
  150. diff2 = slice.get(y) - slice.get(x)
  151.  
  152. switch math.sign(diff1 * diff2)
  153.  
  154. 1 => valMat.set(0, iteration, 1)
  155. -1 => valMat.set(1, iteration, 1)
  156.  
  157. if diff1.equal(0)
  158. valMat.set(2, iteration, 1)
  159.  
  160. if diff2.equal(0)
  161. valMat.set(3, iteration, 1)
  162.  
  163. iteration += 1
  164.  
  165. con = valMat.row(0).sum(), dis = valMat.row(1).sum()
  166. aT = valMat.row(2).sum(), bT = valMat.row(3).sum()
  167.  
  168. fin = (con - dis) / math.sqrt((con + dis + aT) * (con + dis + bT))
  169.  
  170. id.update(fin, i)
  171.  
  172. method determine(bool id, a, b) =>
  173.  
  174. switch id
  175.  
  176. true => a
  177. => b
  178.  
  179. method updateZig(array <line> id, x1, y1, x2, y2) =>
  180.  
  181. id.push(line.new(x1, y1, x2, y2, color = projcol, width = 2))
  182.  
  183. method float (int id) => float(id)
  184.  
  185.  
  186. var zigZag = ZigZagLib.newInstance(
  187. ZigZagLib.Settings.new(
  188. 0.00001, //input.float(0.00001, "Price deviation for reversals (%)", 0.00001, 100.0, 0.5, "0.00001 - 100", group = "Aesthetics"),
  189. 5, //input.int(5, "Pivot legs", 2, group = "Aesthetics"),
  190. #00000000, //input(#2962FF, "Line color", group = "Aesthetics", inline = "1"),
  191. false, //input(true, "Extend to last bar"),
  192. false, //input(false, "Display reversal price", group = "Aesthetics"),
  193. false, //input(false, "Display cumulative volume", group = "Aesthetics"),
  194. false, //input(false, "Display reversal price change", inline = "priceRev", group = "Aesthetics"),
  195. "Absolute", //input.string("Absolute", "", ["Absolute", "Percent"], inline = "priceRev", group = "Aesthetics"),
  196. true)
  197. ), zigZag.update()
  198.  
  199. if typec == "Kendall"
  200.  
  201. tim := math.min(tim, 1500)
  202. historical := math.min(20, historical)
  203.  
  204.  
  205. var closeArr = array.new_float(), var loArr = array.new_float()
  206. var hiArr = array.new_float(), var timeArr = array.new_int (),
  207. mastertime.push(time)
  208.  
  209. if last_bar_index - bar_index <= tim
  210.  
  211. val = switch simtype
  212.  
  213. "%Change" => math.log(close / close[1])
  214. => close
  215.  
  216. timeArr .push(time), closeArr.push(close)
  217. ret .push(val) , loArr .push(low),
  218. hiArr .push(high)
  219.  
  220. if barstate.islastconfirmedhistory
  221.  
  222. lineAll = line.all, box.all.flush()
  223. var xcor = last_bar_index
  224.  
  225. for i = 0 to lineAll.size() - 1
  226. if lineAll.get(i).get_x2() > t
  227.  
  228. for x = mastertime.size() - 1 to 0
  229. if mastertime.get(x).float().equal(lineAll.get(i).get_x2())
  230.  
  231. xcor := x
  232. break
  233.  
  234. if lineAll.size().float().over(0)
  235. for i = lineAll.size() - 1 to 0
  236. if lineAll.get(i).get_x2().float().under(1e8)
  237. lineAll.get(i).delete()
  238.  
  239. recRet := ret.slice(ret.size() - historical, ret.size())
  240.  
  241. switch typec
  242.  
  243. "Spearmen" => result.spearmen()
  244. "Pearson" => result.pearson ()
  245. "Euclidean (Absolute Difference)" => result.euc ()
  246. "Cosine Similarity" => result.cosine ()
  247. "Mean Squared Error" => result.mse ()
  248. "Kendall" => result.kendall ()
  249.  
  250. startarr = int(result.get(1, 0))
  251. midarr = startarr + historical
  252. endarr = midarr + forecastLen
  253.  
  254. float [] lineData = na
  255.  
  256. if simtype == "%Change"
  257. lineData := ret.slice(startarr + historical + 1, endarr + 1)
  258.  
  259. else
  260. lineData := array.new_float()
  261.  
  262. for i = startarr + historical + 1 to endarr
  263. lineData.push(closeArr.get(i) / closeArr.get(i - 1) - 1)
  264.  
  265. projectZig = array.new_line(), lines = array.new_line(), diffArr = array.new_float()
  266.  
  267. if lineAll.size().float().over(0)
  268. for i = 1 to lineAll.size() - 1
  269.  
  270. diffArr.push(math.abs((lineAll.get(i).get_y2() - lineAll.get(i - 1).get_y2()) / lineAll.get(i - 1).get_y2()))
  271.  
  272. lasty2 = lineAll.last().get_y2(), lasty22 = lineAll.get(lineAll.size() - 2).get_y2(),
  273. threshold = diffArr.percentile_nearest_rank(25)
  274.  
  275. lines.push(line.new(bar_index, close, bar_index + 1, close * (1 + lineData.first()),
  276. color = ponly.determine(forecastCol, #00000000),
  277. style = line.style_dotted
  278. ))
  279.  
  280. if zonly
  281.  
  282. projectZig.updateZig(xcor, lineAll.last().get_y2(), bar_index, lasty22.under(lasty2).determine(low, high))
  283.  
  284. for i = 1 to lineData.size() - 1
  285.  
  286. lines.push(
  287.  
  288. line.new(
  289.  
  290. lines.get(i - 1).get_x2(), lines.get(i - 1).get_y2(), lines.get(i - 1).get_x2() + 1,
  291. lines.get(i - 1).get_y2() * (1 + lineData.get(i)), color = ponly.determine(forecastCol, #00000000), style = line.style_dotted))
  292.  
  293. if zonly
  294.  
  295. if projectZig.size().float().equal(1)
  296.  
  297. if lasty22.under(lasty2)
  298.  
  299. var min = 1e8, var max = 0.
  300.  
  301. min := math.min(lines.last().get_y2(), min, projectZig.last().get_y2())
  302.  
  303. switch min.equal(lines.last().get_y2())
  304.  
  305. true => max := 0
  306. => max := math.max(max, lines.last().get_y2())
  307.  
  308. projectZig.last().set_y2(min)
  309. projectZig.last().set_x2(min.equal(lines.last().get_y2()).determine(lines.last().get_x2(), projectZig.last().get_x2()))
  310.  
  311. if math.abs((max - min) / min).over_equal(threshold) and max.not_equal(0)
  312.  
  313. maxmap = map.new<float, int>(), count = hiArr.size() - 1
  314.  
  315. for x = mastertime.size() - 1 to 0
  316. switch mastertime.get(x) > lineAll.last().get_x2()
  317.  
  318. true => maxmap.put(hiArr.get(count), x)
  319. => break
  320.  
  321. count -= 1
  322.  
  323. keymaxx = maxmap.keys()
  324.  
  325. if keymaxx.max() > projectZig.last().get_y1()
  326. projectZig.last().set_xy1(maxmap.get(keymaxx.max()), keymaxx.max())
  327.  
  328.  
  329. projectZig.updateZig(projectZig.last().get_x2(), projectZig.last().get_y2(), lines.last().get_x2(), max)
  330.  
  331. else
  332.  
  333. if i.float().equal(1)
  334.  
  335. min = map.new<float, int>(), count = loArr.size() - 1
  336.  
  337. for x = mastertime.size() - 1 to 0
  338.  
  339. switch mastertime.get(x).float().over_equal(lineAll.last().get_x2())
  340.  
  341. true => min.put(loArr.get(count), x)
  342. => break
  343.  
  344. count -= 1
  345.  
  346. keys = min.keys()
  347.  
  348. if keys.min().under(projectZig.last().get_y2())
  349.  
  350. projectZig.last().set_y2(math.min(keys.min(), lines.last().get_y2()))
  351.  
  352. x2 = switch lines.last().get_y2().under(keys.min())
  353.  
  354. true => lines.last().get_x2()
  355. => min .get(keys.min())
  356.  
  357. projectZig.last().set_x2(x2), projectZig.last().set_x1(mastertime.indexof(lineAll.get(lineAll.size() - 2).get_x2()))
  358. projectZig.last().set_y1(lineAll.get(lineAll.size() - 2).get_y2())
  359.  
  360. projectZig.updateZig(projectZig.last().get_x2(), projectZig.last().get_y2(), lines.last().get_x2(), lines.last().get_y2())
  361.  
  362. var min = 1e8, var max = 0.
  363.  
  364. max := math.max(lines.last().get_y2(), max)
  365.  
  366. switch max.equal(lines.last().get_y2())
  367.  
  368. true => min := 1e8
  369. => min := math.min(min, lines.last().get_y2())
  370.  
  371. projectZig.last().set_y2(max)
  372. projectZig.last().set_x2(max.equal(lines.last().get_y2()).determine(lines.last().get_x2(), projectZig.last().get_x2()))
  373.  
  374. if math.abs((max - min) / min).over_equal(threshold) and min.not_equal(1e8)
  375.  
  376. projectZig.updateZig(projectZig.last().get_x2(), projectZig.last().get_y2(), lines.last().get_x2(), min)
  377.  
  378.  
  379. else if projectZig.size().float().over(1)
  380.  
  381. if projectZig.last().get_y2().over_equal(projectZig.get(projectZig.size() - 2).get_y2())
  382. var max =0., var min = 1e8
  383. max := math.max(max, lines.last().get_y2(), projectZig.last().get_y2())
  384.  
  385. switch max.equal(lines.last().get_y2())
  386.  
  387. true => min := 1e8
  388. => min := math.min(min, lines.last().get_y2())
  389.  
  390. projectZig.last().set_y2(math.max(max, projectZig.last().get_y2()))
  391. projectZig.last().set_x2(max.equal(lines.last().get_y2()).determine(lines.last().get_x2(), projectZig.last().get_x2()))
  392.  
  393. if math.abs((max - min) / min).over_equal(threshold) and min.not_equal(1e8)
  394.  
  395. if projectZig.size().float().over(2)
  396. or projectZig.size().float().equal(2) and projectZig.first().get_y1().equal(lineAll.last().get_y2())
  397.  
  398. projectZig.updateZig(projectZig.last().get_x2(), projectZig.last().get_y2(), lines.last().get_x2(), min)
  399.  
  400.  
  401. else if projectZig.size().float().equal(2)
  402.  
  403. maxx = map.new<float, int>(), count = hiArr.size() - 1
  404.  
  405. for x = mastertime.size() - 1 to 0
  406. switch mastertime.get(x).float().over(lineAll.last().get_x2())
  407.  
  408. true => maxx.put(hiArr.get(count), x)
  409. => break
  410.  
  411. count -= 1
  412.  
  413. keyMax = maxx.keys()
  414.  
  415. if keyMax.max().over(max)
  416. projectZig.last().set_y2(keyMax.max()), projectZig.last().set_x2(maxx.get(keyMax.max()))
  417.  
  418. if projectZig.last().get_x1().float().not_equal(last_bar_index)
  419.  
  420. switch lineAll.last().get_x1().float().over(lineAll.last().get_x2())
  421.  
  422. true => projectZig.last().set_xy1(mastertime.indexof(lineAll.last().get_x1()), lineAll.last().get_y1())
  423. => projectZig.last().set_xy1(mastertime.indexof(lineAll.last().get_x2()), lineAll.last().get_y2())
  424.  
  425. projectZig.remove(projectZig.size() - 2).delete()
  426. projectZig.updateZig(projectZig.last().get_x2(), projectZig.last().get_y2(), lines.last().get_x2(), min)
  427.  
  428. max := 0, min := 1e8
  429.  
  430. else if projectZig.last().get_y2().under(projectZig.get(projectZig.size() - 2).get_y2())
  431.  
  432. var min = 1e8, var max = 0.
  433. min := math.min(lines.last() .get_y2(), min, projectZig.last().get_y2())
  434.  
  435. switch min.equal(lines.last().get_y2())
  436.  
  437. true => max := 0
  438. => max := math.max(max, lines.last().get_y2())
  439.  
  440. projectZig.last().set_y2(min)
  441. projectZig.last().set_x2(min.equal(lines.last().get_y2()).determine(lines.last().get_x2(), projectZig.last().get_x2()))
  442.  
  443. if math.abs((max - min) / min).over_equal(threshold) and max.not_equal(0)
  444.  
  445. if projectZig.size().float().over(1)
  446.  
  447. max := 0, min := 1e8
  448.  
  449. projectZig.updateZig(projectZig.last().get_x2(), projectZig.last().get_y2(), lines.last().get_x2(), lines.last().get_y2())
  450.  
  451.  
  452. if i.float().equal(lineData.size() - 1)
  453. if projectZig.size().float().equal(1)
  454.  
  455. valMap = map.new<float, int>()
  456.  
  457. for x = lines.size() - 1 to 0
  458. switch lines.get(x).get_x2().float().over(projectZig.last().get_x2())
  459.  
  460. true => valMap.put(lines.get(x).get_y2(), x)
  461. => break
  462.  
  463. keys = valMap.keys(), cond = projectZig.last().get_y2().under(projectZig.last().get_y1())
  464.  
  465. [finx, finy] = switch cond
  466.  
  467. true => [valMap.get(keys.max()), keys.max()]
  468. => [valMap.get(keys.min()), keys.min()]
  469.  
  470. projectZig.updateZig(projectZig.last().get_x2(), projectZig.last().get_y2(), bar_index + finx + 1, finy)
  471.  
  472. if on
  473.  
  474. linReg = matrix.new<float>(4, forecastLen)
  475.  
  476. for i = 0 to forecastLen - 1
  477.  
  478. linReg.set(0, i, i + 1), linReg.set(1, i, lines.get(i).get_y2())
  479.  
  480. b = linReg.row(0)
  481.  
  482. for i = 0 to lineData.size() - 1
  483.  
  484. linReg.set(2, i, math.pow(b.get(i) - b.avg(), 2))
  485. linReg.set(3, i, (b.get(i) - b.avg()) * (linReg.row(1).get(i) - linReg.row(1).avg()))
  486.  
  487. bx = linReg.row(3).sum() / linReg.row(2).sum()
  488. mx = linReg.row(1).avg() - (bx * b.avg())
  489.  
  490. upper = line.new(bar_index, (bx + mx) + linReg.row(1).stdev() * stdev, bar_index + linReg.row(1).size(),
  491. (bx * linReg.row(1).size() + mx) + linReg.row(1).stdev() * stdev,
  492. color = #6929F2
  493. )
  494.  
  495. lower = line.new(bar_index, (bx + mx) - linReg.row(1).stdev() * stdev, bar_index + linReg.row(1).size(),
  496. (bx * linReg.row(1).size() + mx) - linReg.row(1).stdev() * stdev,
  497. color = #6929F2
  498. )
  499.  
  500. linefill.new(upper, lower, color.new(#6929F2, 75))
  501.  
  502. slicex = closeArr.slice(startarr, endarr + 1)
  503. sliceHi = hiArr .slice(closeArr.size() - historical, closeArr.size())
  504. sliceLo = loArr .slice(closeArr.size() - historical, closeArr.size())
  505.  
  506. box.new(timeArr.get(startarr), slicex.min(), timeArr.get(midarr), slicex.max(),
  507. bgcolor = color.new(color.blue, 70),
  508. xloc = xloc.bar_time,
  509. border_color = #00000000
  510. )
  511.  
  512. box.new(timeArr.get(midarr), slicex.min(), timeArr.get(endarr), slicex.max(),
  513. bgcolor = color.new(forecastCol, 70),
  514. xloc = xloc.bar_time,
  515. border_color = #00000000
  516. )
  517.  
  518. box.new(bar_index - historical + 1, sliceHi.max(), bar_index, sliceLo.min(),
  519. bgcolor = color.new(color.blue, 80),
  520. border_color = #00000000
  521. )
  522.  
  523. var tab = table.new(position.bottom_right, 5, 5, frame_color = color.white, border_color = color.white, frame_width = 1, border_width = 1)
  524.  
  525. tab.cell(0, 0, text = "Searching " + str.tostring(math.min(last_bar_index, tim), "##") + " Bars Back",
  526. text_color = color.white,
  527. text_size = size.small ,
  528. bgcolor = #00000050)
  529.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement