xmd79

Cryprich Moving Regression

Sep 30th, 2021
245
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.86 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. // © tbiktag
  3. //
  4. // Moving Regression Band Breakout strategy
  5. //
  6. // The strategy based on the Moving Regression Prediction Bands indicator:
  7. //
  8. // https://www.tradingview.com/script/zOaMXJ65-Moving-Regression-Prediction-Bands/
  9. //
  10. // Entry condition:
  11. // Long: the price crosses the Upper Band from below.
  12. // Short: the price crosses the Lower Band from above.
  13. // Exit condition Long:
  14. // the price crosses the Lower Band (the Lower Band - ATR, or Central Line)
  15. // Exit condition Short:
  16. // the price crosses the Upper Band (the Upper Band + ATR, or Central Line)
  17. //
  18. //
  19. //@version=4
  20. strategy("Cryprich Moving Regression ", shorttitle = "Cryp reg2", overlay=true)
  21.  
  22. matrix_get(_A,_i,_j,_nrows) =>
  23. // Get the value of the element of an implied 2d matrix
  24. //input:
  25. // _A :: array: pseudo 2d matrix _A = [[column_0],[column_1],...,[column_(n-1)]]
  26. // _i :: integer: row number
  27. // _j :: integer: column number
  28. // _nrows :: integer: number of rows in the implied 2d matrix
  29. array.get(_A,_i+_nrows*_j)
  30.  
  31. matrix_set(_A,_value,_i,_j,_nrows) =>
  32. // Set a value to the element of an implied 2d matrix
  33. //input:
  34. // _A :: array, changed on output: pseudo 2d matrix _A = [[column_0],[column_1],...,[column_(n-1)]]
  35. // _value :: float: the new value to be set
  36. // _i :: integer: row number
  37. // _j :: integer: column number
  38. // _nrows :: integer: number of rows in the implied 2d matrix
  39. array.set(_A,_i+_nrows*_j,_value)
  40.  
  41. transpose(_A,_nrows,_ncolumns) =>
  42. // Transpose an implied 2d matrix
  43. // input:
  44. // _A :: array: pseudo 2d matrix _A = [[column_0],[column_1],...,[column_(n-1)]]
  45. // _nrows :: integer: number of rows in _A
  46. // _ncolumns :: integer: number of columns in _A
  47. // output:
  48. // _AT :: array: pseudo 2d matrix with implied dimensions: _ncolums x _nrows
  49. var _AT = array.new_float(_nrows*_ncolumns,0)
  50. for i = 0 to _nrows-1
  51. for j = 0 to _ncolumns-1
  52. matrix_set(_AT, matrix_get(_A,i,j,_nrows),j,i,_ncolumns)
  53. _AT
  54.  
  55. multiply(_A,_B,_nrowsA,_ncolumnsA,_ncolumnsB) =>
  56. // Calculate scalar product of two matrices
  57. // input:
  58. // _A :: array: pseudo 2d matrix
  59. // _B :: array: pseudo 2d matrix
  60. // _nrowsA :: integer: number of rows in _A
  61. // _ncolumnsA :: integer: number of columns in _A
  62. // _ncolumnsB :: integer: number of columns in _B
  63. // output:
  64. // _C:: array: pseudo 2d matrix with implied dimensions _nrowsA x _ncolumnsB
  65. var _C = array.new_float(_nrowsA*_ncolumnsB,0)
  66. int _nrowsB = _ncolumnsA
  67. float elementC= 0.0
  68. for i = 0 to _nrowsA-1
  69. for j = 0 to _ncolumnsB-1
  70. elementC := 0
  71. for k = 0 to _ncolumnsA-1
  72. elementC := elementC + matrix_get(_A,i,k,_nrowsA)*matrix_get(_B,k,j,_nrowsB)
  73. matrix_set(_C,elementC,i,j,_nrowsA)
  74. _C
  75.  
  76. vnorm(_X,_n) =>
  77. //Square norm of vector _X with size _n
  78. float _norm = 0.0
  79. for i = 0 to _n-1
  80. _norm := _norm + pow(array.get(_X,i),2)
  81. sqrt(_norm)
  82.  
  83. qr_diag(_A,_nrows,_ncolumns) =>
  84. //QR Decomposition with Modified Gram-Schmidt Algorithm (Column-Oriented)
  85. // input:
  86. // _A :: array: pseudo 2d matrix _A = [[column_0],[column_1],...,[column_(n-1)]]
  87. // _nrows :: integer: number of rows in _A
  88. // _ncolumns :: integer: number of columns in _A
  89. // output:
  90. // _Q: unitary matrix, implied dimenstions _nrows x _ncolumns
  91. // _R: upper triangular matrix, implied dimansions _ncolumns x _ncolumns
  92. var _Q = array.new_float(_nrows*_ncolumns,0)
  93. var _R = array.new_float(_ncolumns*_ncolumns,0)
  94. var _a = array.new_float(_nrows,0)
  95. var _q = array.new_float(_nrows,0)
  96. float _r = 0.0
  97. float _aux = 0.0
  98. //get first column of _A and its norm:
  99. for i = 0 to _nrows-1
  100. array.set(_a,i,matrix_get(_A,i,0,_nrows))
  101. _r := vnorm(_a,_nrows)
  102. //assign first diagonal element of R and first column of Q
  103. matrix_set(_R,_r,0,0,_ncolumns)
  104. for i = 0 to _nrows-1
  105. matrix_set(_Q,array.get(_a,i)/_r,i,0,_nrows)
  106. if _ncolumns != 1
  107. //repeat for the rest of the columns
  108. for k = 1 to _ncolumns-1
  109. for i = 0 to _nrows-1
  110. array.set(_a,i,matrix_get(_A,i,k,_nrows))
  111. for j = 0 to k-1
  112. //get R_jk as scalar product of Q_j column and A_k column:
  113. _r := 0
  114. for i = 0 to _nrows-1
  115. _r := _r + matrix_get(_Q,i,j,_nrows)*array.get(_a,i)
  116. matrix_set(_R,_r,j,k,_ncolumns)
  117. //update vector _a
  118. for i = 0 to _nrows-1
  119. _aux := array.get(_a,i) - _r*matrix_get(_Q,i,j,_nrows)
  120. array.set(_a,i,_aux)
  121. //get diagonal R_kk and Q_k column
  122. _r := vnorm(_a,_nrows)
  123. matrix_set(_R,_r,k,k,_ncolumns)
  124. for i = 0 to _nrows-1
  125. matrix_set(_Q,array.get(_a,i)/_r,i,k,_nrows)
  126. [_Q,_R]
  127.  
  128. pinv(_A,_nrows,_ncolumns) =>
  129. //Pseudoinverse of matrix _A calculated using QR decomposition
  130. // Input:
  131. // _A:: array: implied as a (_nrows x _ncolumns) matrix _A = [[column_0],[column_1],...,[column_(_ncolumns-1)]]
  132. // Output:
  133. // _Ainv:: array implied as a (_ncolumns x _nrows) matrix _A = [[row_0],[row_1],...,[row_(_nrows-1)]]
  134. // ----
  135. // First find the QR factorization of A: A = QR,
  136. // where R is upper triangular matrix.
  137. // Then _Ainv = R^-1*Q^T.
  138. // ----
  139. [_Q,_R] = qr_diag(_A,_nrows,_ncolumns)
  140. _QT = transpose(_Q,_nrows,_ncolumns)
  141. // Calculate Rinv:
  142. var _Rinv = array.new_float(_ncolumns*_ncolumns,0)
  143. float _r = 0.0
  144. matrix_set(_Rinv,1/matrix_get(_R,0,0,_ncolumns),0,0,_ncolumns)
  145. if _ncolumns != 1
  146. for j = 1 to _ncolumns-1
  147. for i = 0 to j-1
  148. _r := 0.0
  149. for k = i to j-1
  150. _r := _r + matrix_get(_Rinv,i,k,_ncolumns)*matrix_get(_R,k,j,_ncolumns)
  151. matrix_set(_Rinv,_r,i,j,_ncolumns)
  152. for k = 0 to j-1
  153. matrix_set(_Rinv,-matrix_get(_Rinv,k,j,_ncolumns)/matrix_get(_R,j,j,_ncolumns),k,j,_ncolumns)
  154. matrix_set(_Rinv,1/matrix_get(_R,j,j,_ncolumns),j,j,_ncolumns)
  155. //
  156. _Ainv = multiply(_Rinv,_QT,_ncolumns,_ncolumns,_nrows)
  157. _Ainv
  158.  
  159. mae(_x, _xhat) =>
  160. // Mean Average Error
  161. // _x. :: array float, original data
  162. // _xhat :: array float, model estimate
  163. // output
  164. // _nrmse:: float
  165. float _mae = 0.0
  166. if array.size(_x) != array.size(_xhat)
  167. _mae := na
  168. else
  169. _N = array.size(_x)
  170. for i = 0 to _N-1
  171. _mae := _mae + abs(array.get(_x,i) - array.get(_xhat,i))/_N
  172. _mae
  173.  
  174. mr(_src,_window,_degree) =>
  175. // Vandermonde matrix with implied dimensions (window x degree+1)
  176. // Linear form: J = [ [z]^0, [z]^1, ... [z]^degree], with z = [ (1-window)/2 to (window-1)/2 ]
  177. var _J = array.new_float(_window*(_degree+1),0)
  178. for i = 0 to _window-1
  179. for j = 0 to _degree
  180. matrix_set(_J,pow(i,j),i,j,_window)
  181. // Vector of raw datapoints:
  182. var _Y_raw = array.new_float(_window,na)
  183. for j = 0 to _window-1
  184. array.set(_Y_raw,j,_src[_window-1-j])
  185. // Calculate polynomial coefficients which minimize the loss function
  186. _C = pinv(_J,_window,_degree+1)
  187. _a_coef = multiply(_C,_Y_raw,_degree+1,_window,1)
  188. // For smoothing, approximate the last point (i.e. z=window-1) by a0
  189. float _Y = 0.0
  190. for i = 0 to _degree
  191. _Y := _Y + array.get(_a_coef,i)*pow(_window-1,i)
  192. // Trend Direction Forecast
  193. float _Y_f = 0.0
  194. for i = 0 to _degree
  195. _Y_f := _Y_f + array.get(_a_coef,i)*pow(_window,i)
  196. // Calculates data estimate (needed for rmse)
  197. _Y_hat = multiply(_J,_a_coef,_window,_degree+1,1)
  198. float _err = mae(_Y_raw,_Y_hat)
  199. [_Y,_Y_f,_err]
  200.  
  201. /// --- main ---
  202. src = input(title="Source", defval=close, group = "Model Parameters:")
  203. degree = input(title="Local Polynomial Degree", type = input.integer, defval=2, minval = 0, group = "Model Parameters:")
  204. // RSI
  205. rsiGroup = "RSI"
  206. lenRSI = input(14, title="Length", minval=1, group=rsiGroup)
  207. // lessThan = input(50, title="Less than", minval=1 , maxval=100, group=rsiGroup)
  208. RSI = rsi(src, lenRSI)
  209.  
  210. // MACD
  211. fast_length = input(title="Fast Length", type=input.integer, defval=12, group="MACD")
  212. slow_length = input(title="Slow Length", type=input.integer, defval=26, group="MACD")
  213. signal_length = input(title="Signal Smoothing", type=input.integer, minval = 1, maxval = 50, defval = 9, group="MACD")
  214. sma_source = input(title="Oscillator MA Type", type=input.string, defval="EMA", options=["SMA", "EMA"], group="MACD")
  215. sma_signal = input(title="Signal Line MA Type", type=input.string, defval="EMA", options=["SMA", "EMA"], group="MACD")
  216. fast_ma = sma_source == "SMA" ? sma(src, fast_length) : ema(src, fast_length)
  217. slow_ma = sma_source == "SMA" ? sma(src, slow_length) : ema(src, slow_length)
  218. macd = fast_ma - slow_ma
  219. signal = sma_signal == "SMA" ? sma(macd, signal_length) : ema(macd, signal_length)
  220.  
  221. window = input(title="Length (must be larger than degree)", type = input.integer, defval=80, minval = 2, group = "Model Parameters:")
  222. mult = input(title="Multiplier", type=input.float,defval=2.0,minval=0.0,group = "Model Parameters:", tooltip = "Defines the Band Width.")
  223. doLong = input(title="Allow Long Entries", type=input.bool,defval=true, inline = "linealwd", group = "Allowed Entries:")
  224. doShort = input(title="Allow Short Entries", type=input.bool,defval=false, inline = "linealwd", group = "Allowed Entries:")
  225. stoplong = input(title="Exit Long At", defval="Central Line",options = ["Lower Band","Upper Band - ATR","Central Line","Upper band"],inline = "lineexit", group = "Exit Conditions:")
  226. stopshort = input(title="Exit Short At", defval="Central Line",options = ["Upper Band","Upper Band + ATR","Central Line", "Lower Band"],inline = "lineexit", group = "Exit Conditions:")
  227. fixedstart =input(title="", group = "Fixed Backtest Period Start/End Dates:",inline = "linebac1", type = input.bool, defval = true)
  228. backtest_start=input(title = "", type = input.time, inline = "linebac1",
  229. group = "Fixed Backtest Period Start/End Dates:",
  230. defval = timestamp("01 Jan 2017 13:30 +0000"),
  231. tooltip="If deactivated, backtest staring from the first available price bar.")
  232. fixedend = input(title="", group = "Fixed Backtest Period Start/End Dates:",
  233. inline = "linebac2", type = input.bool, defval = false)
  234. backtest_end =input(title = "", type = input.time, inline = "linebac2",
  235. group = "Fixed Backtest Period Start/End Dates:",
  236. defval = timestamp("30 Dec 2080 23:30 +0000"),
  237. tooltip="If deactivated, backtesting ends at the last available price bar.")
  238. istoploss = input(title="Show Stop-Loss Line", type=input.bool,defval=true, group="Additional Options")
  239. slopefilter = input(title="Enter Only When MR Slope is Positive/Negative", type=input.bool,defval=false, group="Additional Options")
  240. issignal = input(title="Show Breakout Signals Labels", type=input.bool,defval=false, group="Additional Options")
  241. clinetype = input(title="Show Central Line As", defval="Previous-Period MR Prediction",
  242. options = ["Ribbon","MR","Previous-Period MR Prediction"], group="Additional Options")
  243.  
  244. [MR,MR_f,div] = mr(src,window,degree)
  245. div := div*mult
  246.  
  247.  
  248.  
  249. // plot bands
  250. highband = MR_f[1]+div[1]
  251. lowband = MR_f[1]-div[1]
  252. centralline = MR_f[1]
  253. hbplt = plot(highband,title='Upper Band',color=#3C94B8,linewidth=2, transp = 40)
  254. lbplt = plot(lowband,title='Lower Band',color=#B83C94,linewidth=2, transp = 40)
  255. fill(hbplt,lbplt,color=#3C94B8)
  256.  
  257. // plot central line
  258. var plt_color = #3C94B8
  259. if MR_f[1] < MR and clinetype=="Ribbon"
  260. plt_color := #94B83C
  261. else if MR_f[1] > MR and clinetype=="Ribbon"
  262. plt_color := #B83C71
  263. mrplt = plot(MR,title='MR',color=plt_color,linewidth=1,
  264. transp = clinetype=="Previous-Period MR Prediction"?100:20)
  265. mrfplt = plot(centralline,title='MR Prediction',color=plt_color,linewidth=1,
  266. transp = clinetype=="MR"?100:20)
  267. fill(mrplt,mrfplt,color=plt_color,transp = clinetype!="Ribbon"?100:20)
  268.  
  269.  
  270. // breakout signals
  271. ATR = atr(14)
  272. Breakout = crossover(src,highband)
  273. Breakdown = crossunder(src,lowband)
  274. ATRBreakout = crossover(src,highband + ATR)
  275. ATRBreakdown = crossunder(src,lowband - ATR)
  276. MRSlopesUp = MR>MR[1]
  277. MRSlopesDw = MR<MR[1]
  278. plotshape(Breakout and issignal ? high : na, location=location.abovebar,
  279. style=shape.triangleup, color=#88d4ca, size=size.tiny, title='Breakout')
  280. plotshape(Breakdown and issignal? low : na, location=location.belowbar,
  281. style=shape.triangledown, color=#f67e7d, size=size.tiny,title='Breakdown')
  282. goLong = Breakdown and (slopefilter?MRSlopesUp:true) and RSI < 30
  283. goShort = Breakout and (slopefilter?MRSlopesDw:true) and RSI > 60
  284. // Strategy Conditions
  285.  
  286. // trailing stop / stop loss
  287. trailinglong = stoplong=="Central Line"?centralline:(stoplong=="Lower Band"?lowband:lowband-ATR)
  288. trailingshort= stopshort=="Central Line"?centralline:(stopshort=="Upper Band"?highband:highband+ATR)
  289. // if signal has been triggered at previous bar, set position open price and initial SL
  290. var float opprice = 0.0
  291. var float stoploss = 0.0
  292. if (strategy.position_entry_name[1]=="short" or strategy.position_size[1]==0) and goLong[1]
  293. opprice := open
  294. stoploss := trailinglong
  295. else if (strategy.position_entry_name[1]=="long" or strategy.position_size[1]==0) and goShort[1]
  296. opprice := open
  297. stoploss := trailingshort
  298. // move SL to position opening price if lowband crosses the initial SL
  299. if (strategy.position_entry_name=="long" and crossover(trailinglong, opprice)) or (strategy.position_entry_name=="short" and crossunder(trailingshort, opprice))
  300. stoploss := opprice
  301. stoplosscolor = strategy.position_entry_name=="long"?#B83C94:(strategy.position_entry_name=="short"?#3C94B8:color.silver)
  302. plot(istoploss?stoploss:na,title='sl',color=stoplosscolor,linewidth=1,transp=50)
  303.  
  304. endLong = crossunder(src,trailinglong)
  305. endShort = crossover(src,trailingshort)
  306.  
  307. // backtest
  308. isinrange = (fixedstart?time>=backtest_start:true) and (fixedend?time<=backtest_end:true)
  309.  
  310. if goLong and isinrange and doLong
  311. strategy.entry("long", true)
  312. alert(syminfo.tickerid+" Long Signal Triggered",alert.freq_once_per_bar_close)
  313. if goShort and isinrange and doShort
  314. strategy.entry("short", false)
  315. alert(syminfo.tickerid+" Short Signal Triggered",alert.freq_once_per_bar_close)
  316. if endLong or crossunder(src,stoploss)
  317. strategy.close("long")
  318. alert(syminfo.tickerid+" Exit Signal Triggered for Long Position",alert.freq_once_per_bar_close)
  319. if endShort or crossover(src,stoploss)
  320. strategy.close("short")
  321. alert(syminfo.tickerid+" Exit Signal Triggered for Short Position",alert.freq_once_per_bar_close)
  322. if (not isinrange)
  323. strategy.close_all()
  324.  
  325.  
  326.  
  327.  
Advertisement
Add Comment
Please, Sign In to add comment