readyset-liqd

price away from moving average strategy

Jan 20th, 2023 (edited)
426
0
Never
1
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.25 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. // © danielx888
  3.  
  4. //@version=5
  5. strategy('MA mean reversion strategy', overlay=true, initial_capital = 5000, default_qty_value = 10000, slippage=20)
  6.  
  7. // USER INPUTS
  8. i_src = input.source(close, 'MA source', group="MA Settings")
  9. i_maLen = input.int(200,'MA length',0, group="MA Settings")
  10. i_maType = input.string('SMA', 'MA type', options=['SMA', 'HMA', 'EMA', 'SMMA (RMA)', 'WMA', 'VWMA'], group="MA Settings")
  11. i_numStdev = input.float(2,'Number of standard deviations away from MA for trigger', 0.1, step=0.1,group='StDev Settings')
  12. i_lookbackMult = input.int(10,'Multiple of MA to lookback for StDev length',1, step=1,group='StDev Settings')
  13. i_excludeInitial = input.bool(true, 'Exclude initial bars until bands are fully developed', 'Recommended to leave this feature enabled. If disabled, strategy may "repaint" ' +
  14. 'the first trades as tradingview chops off the bars at the start of the chart. If disabled, this becomes an even larger issue with a higher "Multiple of MA" entered.')
  15. s_closeAll = input.bool(true, 'Close out position on reversal', group='Trade Management')
  16. i_minimumMove = input.string('StDev','Select criteria to filter out trades if price hasn\'t moved from last entry',['StDev','Flat','None'], group='Trade Management')
  17. i_moveStDev = input.float(0.5,'Number of St Deviations for price to move (select -StDev- above)',0,step=0.01, group='Trade Management')
  18. i_moveFlat = input.float(0.1, 'Flat % for price to move (select -Flat- above)',0,step=0.01, group='Trade Management')/100
  19. i_lag = input.int(1, 'Slope lag', 1,20,1, group='Slope Settings')
  20. i_slopeMult = input.int(1, 'Slope multiplier', 1,10,1, group='Slope Settings')
  21. i_slopeStDev = input.float(2, 'Number of standard deviations of slope change', 0.1, step=0.1,group='Slope Settings')
  22. i_shading = input.bool(false, 'Shade areas between bands where slope is at extremes', group='Slope Settings')
  23.  
  24. // CALCULATE MOVING AVERAGE
  25. ma(source, length, type) =>
  26. switch type
  27. "SMA" => ta.sma(source, length)
  28. "HMA" => ta.hma(source, length)
  29. "EMA" => ta.ema(source, length)
  30. "SMMA (RMA)" => ta.rma(source, length)
  31. "WMA" => ta.wma(source, length)
  32. "VWMA" => ta.vwma(source, length)
  33.  
  34. ma = ma(i_src, i_maLen, i_maType)
  35. lookback = i_maLen * i_lookbackMult
  36. color c = na
  37.  
  38. // CALCULATE STANDARD DEVIATION FOR DISTANCE OF PRICE TO MOVING AVERAGE
  39. //****
  40. // need to fix arrays starting out as all 0s then slowly filling. during the first few hundred bars of strategy opening
  41. // the bands are too tight as the arrays are not fully filled yet. Possible fix to initiliaze array size as 0 and
  42. // use an if statement array length > lookback then array.shift. Implement the same new logic below at the section to calculate
  43. // standard deviation of slope
  44. //****
  45. var a_aboveMA = array.new_float()
  46. var a_belowMA = array.new_float()
  47. if i_src > ma
  48. array.push(a_aboveMA, i_src - ma)
  49. if array.size(a_aboveMA) > lookback
  50. array.shift(a_aboveMA)
  51. if i_src < ma
  52. array.push(a_belowMA, ma - i_src)
  53. if array.size(a_belowMA) > lookback
  54. array.shift(a_belowMA)
  55.  
  56. stdevAbove = array.stdev(a_aboveMA) * i_numStdev
  57. stdevBelow = array.stdev(a_belowMA) * i_numStdev
  58. overbought = i_src > ma and i_src - ma > stdevAbove
  59. oversold = i_src < ma and ma - i_src > stdevBelow
  60. upCandle = close >= open
  61. downCandle = close <= open
  62. doji = open == close
  63.  
  64. // VISUAL SETTINGS FOR DISTANCE TO MOVING AVERAGE
  65. var ob = 0
  66. var os = 0
  67. if overbought
  68. ob := 1
  69. c := color.red
  70. if oversold
  71. os := 1
  72. c := color.green
  73. dn = close > ma and overbought[1] and downCandle and upCandle[1]
  74. up = close < ma and oversold[1] and upCandle and downCandle[1]
  75. if dn
  76. ob := 0
  77. if up
  78. os := 0
  79.  
  80. // DEFINE CANDLE REVERSAL PRICE ACTION
  81. var count = 0
  82. var float diff = 0
  83.  
  84. dnMark = (dn and not dn[1] and not dn[2]) or (ob == 1 and upCandle[1] and downCandle and (ta.barssince(dn) <= ta.barssince(upCandle)))
  85. upMark = (up and not up[1] and not up[2]) or (os == 1 and downCandle[1] and upCandle and (ta.barssince(up) <= ta.barssince(downCandle)))
  86.  
  87. if dnMark
  88. ob := 0
  89. count +=1
  90. diff += (i_src-ma)
  91. if upMark
  92. os := 0
  93. count +=1
  94. diff -= (ma-i_src)
  95.  
  96. // CALCULATE STANDARD DEVIATION FOR SLOPE OF MOVING AVERAGE
  97. slopeLookback = i_maLen * i_slopeMult
  98. laggingMA = ma[i_lag]
  99. var a_slopeUp = array.new_float()
  100. var a_slopeDn = array.new_float()
  101. upSlope = ma > laggingMA
  102. upDiff = ma - laggingMA
  103. if upSlope
  104. array.push(a_slopeUp, upDiff)
  105. if array.size(a_slopeUp) > slopeLookback
  106. array.shift(a_slopeUp)
  107. dnSlope = ma < laggingMA
  108. dnDiff = laggingMA - ma
  109. if dnSlope
  110. array.push(a_slopeDn, dnDiff)
  111. if array.size(a_slopeDn) > slopeLookback
  112. array.shift(a_slopeDn)
  113. stdevUpSlope = array.stdev(a_slopeUp) * i_slopeStDev
  114. stdevDnSlope = array.stdev(a_slopeDn) * i_slopeStDev
  115.  
  116. // DEFINE COLOR CHANGE FOR SLOPE
  117. colNeutral = color.gray
  118. colFastUp = color.green
  119. colFastDn = color.red
  120. colUpShading = color.rgb(76, 175, 79, 80)
  121. colDnShading = color.rgb(255, 82, 82, 80)
  122.  
  123. color col = na
  124. if upSlope and upDiff > stdevUpSlope
  125. col := colFastUp
  126. else if dnSlope and dnDiff > stdevDnSlope
  127. col := colFastDn
  128. else
  129. col := colNeutral
  130.  
  131. color fillCol = na
  132. if i_shading
  133. fillCol := col == colFastUp ? colUpShading : col == colFastDn ? colDnShading : na
  134.  
  135. // DEFINE LIMITS FOR MINIMUM MOVES TO CONSIDER OPENING NEW POSITION
  136. priceMovedShorts =
  137. i_minimumMove == 'None' ? true :
  138. i_minimumMove == 'StDev' ? close > close[ta.barssince(strategy.position_size != strategy.position_size[1])+1] + i_moveStDev*stdevAbove :
  139. i_minimumMove == 'Flat' ? close > close[ta.barssince(strategy.position_size != strategy.position_size[1])+1] * (1+i_moveFlat) : na
  140. priceMovedLongs =
  141. i_minimumMove == 'None' ? true :
  142. i_minimumMove == 'StDev' ? close < close[ta.barssince(strategy.position_size != strategy.position_size[1])+1] - i_moveStDev*stdevBelow :
  143. i_minimumMove == 'Flat' ? close < close[ta.barssince(strategy.position_size != strategy.position_size[1])+1] * (1-i_moveFlat) : na
  144.  
  145. excludeDn = i_excludeInitial ? array.size(a_aboveMA) == lookback : true
  146. excludeUp = i_excludeInitial ? array.size(a_belowMA) == lookback : true
  147. // OPEN AND CLOSE POSITIONS
  148. if dnMark and excludeDn
  149. if ta.barssince(dnMark[1]) > ta.barssince(upMark[1]) or priceMovedShorts or strategy.closedtrades + strategy.opentrades == 0
  150. if s_closeAll and strategy.position_size > 0
  151. strategy.close_all()
  152. strategy.order('Short',strategy.short)
  153. if upMark and excludeUp
  154. if ta.barssince(upMark[1]) > ta.barssince(dnMark[1]) or priceMovedLongs or strategy.closedtrades + strategy.opentrades == 0
  155. if s_closeAll and strategy.position_size < 0
  156. strategy.close_all()
  157. strategy.order('Long',strategy.long)
  158.  
  159. // DEBUG
  160. // label.new(bar_index,high, "array length: " + str.tostring(array.size(a_aboveMA)), color=color.white, style=label.style_label_down, textcolor=color.black)
  161.  
  162. // PLOT VISUALS
  163. plotchar(dnMark, 'dn char', '𝅏', location.abovebar)
  164. plotchar(upMark, 'up char', '▴', location.belowbar)
  165. barcolor(c)
  166. p1 = plot(ma, color=col)
  167. p2 = plot(ma+stdevAbove, color=col)
  168. p3 = plot(ma-stdevBelow, color=col)
  169. fill(p2, p3, color=fillCol)
Advertisement
Comments
  • readyset-liqd
    2 years
    # text 0.20 KB | 0 0
    1. Just realized this repaints the first trades as time moves on and TradingView chops off the first bars. Edited the strategy to wait until bands are fully developed for more accurate backtesting results
Add Comment
Please, Sign In to add comment