Advertisement
xmd79

Session candles & session reversals (+ Backtest)

Jan 12th, 2023
138
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 37.75 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. // © quantifytools
  3.  
  4. //@version=5
  5. indicator("Session candles & session reversals (+ Backtest)", max_boxes_count=500, max_lines_count=500, max_labels_count=500, overlay=true)
  6.  
  7. // Inputs
  8.  
  9. //Session time, session candle offset and show/hide session candle
  10. groupSession = "Sessions"
  11.  
  12. //Session 1 (London)
  13. show_london = input(title='Show session #1', defval=true, inline="london", group=groupSession)
  14. i_londonOffset = input.int(0, "", inline="london", minval=0, group=groupSession, tooltip="Moves candle forward by specified amount of bars.")
  15. london = input.session(title="Session #1 period", defval='0800-1700', tooltip="London by default (UTC)", group=groupSession)
  16.  
  17. //Session 2 (New York)
  18. show_ny = input(title='Show session #2', defval=true, inline="ny", group=groupSession)
  19. i_nyOffset = input.int(0, "", inline="ny", minval=0, group=groupSession)
  20. ny = input.session(title="Session #2 period", defval='1300-2200', tooltip="New York by default (UTC)", group=groupSession)
  21.  
  22. //Session 3 (Sydney)
  23. show_sydney = input(title='Show session #3', defval=true, inline="sydney", group=groupSession)
  24. i_sydneyOffset = input.int(0, "", inline="sydney", minval=0, group=groupSession)
  25. sydney = input.session(title="Session #3 period", defval='2100-0600', tooltip="Sydney by default (UTC)", group=groupSession)
  26.  
  27. //Session 4 (Tokyo)
  28. show_tokyo = input(title='Show session #4', defval=true, inline="tokyo", group=groupSession)
  29. i_tokyoOffset = input.int(0, "", inline="tokyo", minval=0, group=groupSession)
  30. tokyo = input.session(title="Session #4 period", defval='0000-0900', tooltip="Tokyo by default (UTC)", group=groupSession)
  31.  
  32. //Session moving average type, length and selected sessions for MA
  33. groupMa = "Session moving average"
  34.  
  35. i_smoothingType = input.string("SMA", "", options=["SMA", "EMA", "HMA", "RMA", "WMA"], group=groupMa, inline="ma")
  36. i_sessionMaLength = input.int(20, "", group=groupMa, inline="ma")
  37.  
  38. i_useSession1Ma = input.bool(true, "Include session #1", group=groupMa)
  39. i_useSession2Ma = input.bool(true, "Include session #2", group=groupMa)
  40. i_useSession3Ma = input.bool(true, "Include session #3", group=groupMa)
  41. i_useSession4Ma = input.bool(true, "Include session #4", group=groupMa)
  42.  
  43. //Hide chart candles/bars, highlight sessions for selected session candles, hide timeframe notification, numerize sessions
  44. groupChart = "Chart"
  45.  
  46. i_highlightBt = input.string("None", "Highlight backtesting visuals", options=["None", "Session #1", "Session #2", "Session #3", "Session #4"], group=groupChart)
  47. i_hideChart = input.bool(true, "Hide chart", tooltip="", group=groupChart)
  48. i_highlightSession = input.bool(false, "Highlight session periods", group=groupChart, tooltip="Highlights session periods on chart background.")
  49. i_numberedSessions = input.bool(false, "Numerize sessions", group=groupChart, tooltip="Replaces L, N, S, T with 1, 2, 3, 4. Helps with custom sessions.")
  50. i_hideNotification = input.bool(false, "Hide timeframe notification", group=groupChart, tooltip="Hides timeframe notification that pops up when timeframe is > 1 hour.")
  51.  
  52. //Colors
  53. groupColor= "Colors"
  54.  
  55. i_maColUp = input.color(color.green, "MA ▲", group=groupColor, inline="ma")
  56. i_maColDown = input.color(color.red, "MA ▼", group=groupColor, inline="ma")
  57.  
  58. i_londonColUp = input.color(#c8e6c9, "Session #1 ▲", group=groupColor, inline="session1")
  59. i_londonColDown = input.color(#faa1a4, "Session #1 ▼", group=groupColor, inline="session1")
  60. i_londonColSession = input.color(color.gray, "Session #1 ON", group=groupColor, inline="session1", tooltip="Session background color. Visible only if enabled.")
  61.  
  62. i_nyColUp = input.color(#81c784, "Session #2 ▲", group=groupColor, inline="session2")
  63. i_nyColDown = input.color(#f46166, "Session #2 ▼", group=groupColor, inline="session2")
  64. i_nyColSession = input.color(color.black, "Session #2 ON", group=groupColor, inline="session2")
  65.  
  66. i_sydneyColUp = input.color(#05900b, "Session #3 ▲", group=groupColor, inline="session3")
  67. i_sydneyColDown = input.color(#f23645, "Session #3 ▼", group=groupColor, inline="session3")
  68. i_sydneyColSession = input.color(color.blue, "Session #3 ON", group=groupColor, inline="session3")
  69.  
  70. i_tokyoColUp = input.color(#004505, "Session #4 ▲", group=groupColor, inline="session4")
  71. i_tokyoColDown = input.color(#880e4f, "Session #4 ▼", group=groupColor, inline="session4")
  72. i_tokyoColSession = input.color(color.navy, "Session #4 ON", group=groupColor, inline="session4")
  73.  
  74.  
  75. // Session start, on and end functions
  76.  
  77. sessionStart(session) =>
  78. na(time(timeframe.period, session, "GMT"))[1] and not na(time(timeframe.period, session, "GMT"))
  79.  
  80. sessionOn(session) =>
  81. not na(time(timeframe.period, session, "GMT"))
  82.  
  83. sessionEnd(session) =>
  84. na(time(timeframe.period, session, "GMT")) and not na(time(timeframe.period, session, "GMT"))[1]
  85.  
  86.  
  87. // Session OHLC arrays
  88.  
  89. //London
  90. var londonOpen = array.new_float(0, 0)
  91. var londonHigh = array.new_float(0, 0)
  92. var londonLow = array.new_float(0, 0)
  93. var londonClose = array.new_float(0, 0)
  94.  
  95. recentLondonOpen = array.size(londonOpen) > 0 ? array.get(londonOpen, 0) : na
  96. recentLondonHigh = array.size(londonHigh) > 0 ? array.get(londonHigh, 0) : na
  97. recentLondonLow = array.size(londonLow) > 0 ? array.get(londonLow, 0) : na
  98. recentLondonClose = array.size(londonClose) > 0 ? array.get(londonClose, 0) : na
  99.  
  100. //New York
  101. var nyOpen = array.new_float(0, 0)
  102. var nyHigh = array.new_float(0, 0)
  103. var nyLow = array.new_float(0, 0)
  104. var nyClose = array.new_float(0, 0)
  105.  
  106. recentNyOpen = array.size(nyOpen) > 0 ? array.get(nyOpen, 0) : na
  107. recentNyHigh = array.size(nyHigh) > 0 ? array.get(nyHigh, 0) : na
  108. recentNyLow = array.size(nyLow) > 0 ? array.get(nyLow, 0) : na
  109. recentNyClose = array.size(nyClose) > 0 ? array.get(nyClose, 0) : na
  110.  
  111. //Sydney
  112. var sydneyOpen = array.new_float(0, 0)
  113. var sydneyHigh = array.new_float(0, 0)
  114. var sydneyLow = array.new_float(0, 0)
  115. var sydneyClose = array.new_float(0, 0)
  116.  
  117. recentSydneyOpen = array.size(sydneyOpen) > 0 ? array.get(sydneyOpen, 0) : na
  118. recentSydneyHigh = array.size(sydneyHigh) > 0 ? array.get(sydneyHigh, 0) : na
  119. recentSydneyLow = array.size(sydneyLow) > 0 ? array.get(sydneyLow, 0) : na
  120. recentSydneyClose = array.size(sydneyClose) > 0 ? array.get(sydneyClose, 0) : na
  121.  
  122. //Tokyo
  123. var tokyoOpen = array.new_float(0, 0)
  124. var tokyoHigh = array.new_float(0, 0)
  125. var tokyoLow = array.new_float(0, 0)
  126. var tokyoClose = array.new_float(0, 0)
  127.  
  128. recentTokyoOpen = array.size(tokyoOpen) > 0 ? array.get(tokyoOpen, 0) : na
  129. recentTokyoHigh = array.size(tokyoHigh) > 0 ? array.get(tokyoHigh, 0) : na
  130. recentTokyoLow = array.size(tokyoLow) > 0 ? array.get(tokyoLow, 0) : na
  131. recentTokyoClose = array.size(tokyoClose) > 0 ? array.get(tokyoClose, 0) : na
  132.  
  133.  
  134. // Session calculations
  135.  
  136. //Initializing session highest high/lowest low trackers
  137. var float londonHh = 0
  138. var float londonLl = 0
  139.  
  140. var float nyHh = 0
  141. var float nyLl = 0
  142.  
  143. var float sydneyHh = 0
  144. var float sydneyLl = 0
  145.  
  146. var float tokyoHh = 0
  147. var float tokyoLl = 0
  148.  
  149. //London calculations
  150.  
  151. //If session starts, add open to array, high to HH tracker, low to LL tracker
  152. if sessionStart(london)
  153. array.unshift(londonOpen, open)
  154. londonHh := high
  155. londonLl := low
  156.  
  157. //If session is on and high > HH tracker value, replace HH tracker value with high
  158. if sessionOn(london) and high > londonHh[1]
  159. londonHh := high
  160.  
  161. //If session is on and low < LL tracker value, replace LL tracker value with low
  162. if sessionOn(london) and low < londonLl[1]
  163. londonLl := low
  164.  
  165. //If session has ended, add session close (candle open, because session ended 1 time period ago) and add highest high/lowest low to session arrays
  166. if sessionEnd(london)
  167. array.unshift(londonClose, open)
  168. array.unshift(londonHigh, londonHh)
  169. array.unshift(londonLow, londonLl)
  170.  
  171. //Repeating above steps for all other sessions.
  172.  
  173. //New York calculations
  174. if sessionStart(ny)
  175. array.unshift(nyOpen, open)
  176. nyHh := high
  177. nyLl := low
  178.  
  179. if sessionOn(ny) and high > nyHh[1]
  180. nyHh := high
  181.  
  182. if sessionOn(ny) and low < nyLl[1]
  183. nyLl := low
  184.  
  185. if sessionEnd(ny)
  186. array.unshift(nyClose, open)
  187. array.unshift(nyHigh, nyHh)
  188. array.unshift(nyLow, nyLl)
  189.  
  190. //Sydney calculations
  191. if sessionStart(sydney)
  192. array.unshift(sydneyOpen, open)
  193. sydneyHh := high
  194. sydneyLl := low
  195.  
  196. if sessionOn(sydney) and high > sydneyHh[1]
  197. sydneyHh := high
  198.  
  199. if sessionOn(sydney) and low < sydneyLl[1]
  200. sydneyLl := low
  201.  
  202. if sessionEnd(sydney)
  203. array.unshift(sydneyClose, open)
  204. array.unshift(sydneyHigh, sydneyHh)
  205. array.unshift(sydneyLow, sydneyLl)
  206.  
  207. //Tokyo calculations
  208. if sessionStart(tokyo)
  209. array.unshift(tokyoOpen, open)
  210. tokyoHh := high
  211. tokyoLl := low
  212.  
  213. if sessionOn(tokyo) and high > tokyoHh[1]
  214. tokyoHh := high
  215.  
  216. if sessionOn(tokyo) and low < tokyoLl[1]
  217. tokyoLl := low
  218.  
  219. if sessionEnd(tokyo)
  220. array.unshift(tokyoClose, open)
  221. array.unshift(tokyoHigh, tokyoHh)
  222. array.unshift(tokyoLow, tokyoLl)
  223.  
  224. //Function to keep array sizes fixed
  225. arraySize(sessionOpen, sessionHigh, sessionLow, sessionClose) =>
  226.  
  227. sizeLimit = 2
  228.  
  229. if array.size(sessionOpen) >sizeLimit
  230. array.remove(sessionOpen, sizeLimit)
  231. array.remove(sessionHigh, sizeLimit)
  232. array.remove(sessionLow, sizeLimit)
  233. array.remove(sessionClose, sizeLimit)
  234.  
  235. //Clearing arrays
  236. arraySize(londonOpen, londonHigh, londonLow, londonClose)
  237. arraySize(nyOpen, nyHigh, nyLow, nyClose)
  238. arraySize(sydneyOpen, sydneyHigh, sydneyLow, sydneyClose)
  239. arraySize(tokyoOpen, tokyoHigh, tokyoLow, tokyoClose)
  240.  
  241.  
  242. // Session moving average
  243.  
  244. //Function for user defined smoothing method
  245. smoothedValue(source, length) =>
  246. i_smoothingType == "SMA" ? ta.sma(source, length) :
  247. i_smoothingType == "EMA" ? ta.ema(source, length) :
  248. i_smoothingType == "HMA" ? ta.hma(source, length) :
  249. i_smoothingType == "RMA" ? ta.rma(source, length) : ta.wma(source, length)
  250.  
  251. //Session MA's, if not included use 0
  252. londonSma = i_useSession1Ma ? smoothedValue(recentLondonClose, i_sessionMaLength) : 0
  253. nySma = i_useSession2Ma ? smoothedValue(recentNyClose, i_sessionMaLength) : 0
  254. sydneySma = i_useSession3Ma ? smoothedValue(recentSydneyClose, i_sessionMaLength) : 0
  255. tokyoSma = i_useSession4Ma ? smoothedValue(recentTokyoClose, i_sessionMaLength) : 0
  256.  
  257. //Calculate amount of sessions included in MA calculation
  258. int maDivider = 0
  259.  
  260. if i_useSession1Ma
  261. maDivider += 1
  262.  
  263. if i_useSession2Ma
  264. maDivider += 1
  265.  
  266. if i_useSession3Ma
  267. maDivider += 1
  268.  
  269. if i_useSession4Ma
  270. maDivider += 1
  271.  
  272. //Selected session MA's divided by amount of selected sessions
  273. hybridSma = (nySma + tokyoSma + londonSma + sydneySma) / maDivider
  274.  
  275.  
  276. // Session reversals
  277.  
  278. //Session reversal function with session OHLC variables
  279. sessionReversal(sessionOpen, sessionHigh, sessionLow, sessionClose) =>
  280.  
  281. //Position of session close relative to range (high - low)
  282. sessionPos = (sessionClose - sessionLow) / (sessionHigh - sessionLow)
  283.  
  284. //Position of session open relative to range (high - low)
  285. sessionOpenPos = (sessionOpen - sessionLow) / (sessionHigh - sessionLow)
  286.  
  287. //Session high lower than previous high, session low lower than previous low, close >= 65% position (1% being low, 100% being high) and session open at >= 40% position relative to range. A wick up.
  288. wickUp = sessionHigh < sessionHigh[1] and sessionLow < sessionLow[1] and sessionPos >= 0.65 and sessionOpenPos >= 0.40
  289.  
  290. //Session high higher than previous high, session low higher than previous low, close <= 35% position and session open <= 60% position relative to range. A wick down.
  291. wickDown = sessionHigh > sessionHigh[1] and sessionLow > sessionLow[1] and sessionPos <= 0.35 and sessionOpenPos <= 0.60
  292.  
  293. //Session high higher than previous high, session low lower than previous low and close position at same 65%/35% values. Engulfing candle up/down.
  294. engulfUp = sessionHigh > sessionHigh[1] and sessionLow < sessionLow[1] and sessionPos >= 0.65
  295. engulfDown = sessionHigh > sessionHigh[1] and sessionLow < sessionLow[1] and sessionPos <= 0.35
  296.  
  297.  
  298. [wickUp, wickDown, engulfUp, engulfDown]
  299.  
  300. //Fetching session reversals for each session
  301. [wickUpLondon, wickDownLondon, engulfUpLondon, engulfDownLondon] = sessionReversal(recentLondonOpen, recentLondonHigh, recentLondonLow, recentLondonClose)
  302. [wickUpNy, wickDownNy, engulfUpNy, engulfDownNy] = sessionReversal(recentNyOpen, recentNyHigh, recentNyLow, recentNyClose)
  303. [wickUpSydney, wickDownSydney, engulfUpSydney, engulfDownSydney] = sessionReversal(recentSydneyOpen, recentSydneyHigh, recentSydneyLow, recentSydneyClose)
  304. [wickUpTokyo, wickDownTokyo, engulfUpTokyo, engulfDownTokyo] = sessionReversal(recentTokyoOpen, recentTokyoHigh, recentTokyoLow, recentTokyoClose)
  305.  
  306.  
  307. // Session reversal backtest
  308.  
  309. //Sessions are backtested by calculating odds of next matching session closing in supporting direction, known as win rate.
  310. //Magnitude is measured by calculating percentage increase/decrease between session reversal close and next session high/low. This calculation is done only when a reversal is succesful (closes higher/lower compared previous matching session).
  311.  
  312. //Session reversal backtest function
  313. sessionReversalBt(wickUp, wickDown, engulfUp, engulfDown, sessionClose, sessionHigh, sessionLow, session) =>
  314.  
  315. //Get bar_index space between sessions
  316. btPeriod = ta.valuewhen(sessionEnd(session), bar_index, 0) - ta.valuewhen(sessionEnd(session), bar_index, 1)
  317.  
  318. //Initializing counters
  319. var int sessionRevUpCount = 0
  320. var int sessionRevDownCount = 0
  321.  
  322. var int succesfulRevUpCount = 0
  323. var int succesfulRevDownCount = 0
  324.  
  325. var float revUpDepth = 0
  326. var float revDownDepth = 0
  327.  
  328. //Any reversal up/down, either wick or engulfing.
  329. anyRevUp = wickUp or engulfUp
  330. anyRevDown = wickDown or engulfDown
  331.  
  332. //Add 1 to reversal counter when session reversal occurs
  333. if anyRevUp
  334. sessionRevUpCount += 1
  335. else
  336. if anyRevDown
  337. sessionRevDownCount += 1
  338.  
  339. //If session closes higher than previous session and previous session was a reversal, add 1 to succesful reversal counter. Add percentage increase (from previous session close to current session high) to magnitude counter.
  340. if sessionClose > sessionClose[1] and anyRevUp[btPeriod]
  341. succesfulRevUpCount += 1
  342. revUpDepth += (sessionHigh / sessionClose[1]) - 1
  343.  
  344. //Same, but for reversals down
  345. if sessionClose < sessionClose[1] and anyRevDown[btPeriod]
  346. succesfulRevDownCount += 1
  347. revDownDepth += (sessionLow / sessionClose[1]) - 1
  348.  
  349. //Form win rates by dividing succesful reversal count with total reversal count
  350. revUpWr = math.round((succesfulRevUpCount / sessionRevUpCount) * 100, 0)
  351. revDownWr = math.round((succesfulRevDownCount / sessionRevDownCount) * 100, 0)
  352.  
  353. //Form average magnitude by dividing percentage increase/decrease with total reversal count
  354. revUpMagnitude = math.round((revUpDepth / sessionRevUpCount) * 100, 2)
  355. revDownMagnitude = math.round((revDownDepth / sessionRevDownCount) * 100, 2)
  356.  
  357. [sessionRevUpCount, sessionRevDownCount, succesfulRevDownCount, succesfulRevUpCount, revUpDepth, revDownDepth,
  358. revUpWr, revDownWr, revUpMagnitude, revDownMagnitude]
  359.  
  360. //Fetching backtest results for each session reversal
  361. [revUpsLondon, revDownsLondon, sRevDownsLondon, sRevUpsLondon, LondonUpDepth, LondonDownDepth,
  362. LondonRevUpWr, LondonRevDownWr, LondonRevUpMagnitude, LondonRevDownMagnitude]
  363. = sessionReversalBt(wickUpLondon, wickDownLondon, engulfUpLondon, engulfDownLondon, recentLondonClose, recentLondonHigh, recentLondonLow, london)
  364.  
  365. [revUpsNy, revDownsNy, sRevDownsNy, sRevUpsNy, NyUpDepth, NyDownDepth,
  366. NyRevUpWr, NyRevDownWr, NyRevUpMagnitude, NyRevDownMagnitude]
  367. = sessionReversalBt(wickUpNy, wickDownNy, engulfUpNy, engulfDownNy, recentNyClose, recentNyHigh, recentNyLow, ny)
  368.  
  369. [revUpsSydney, revDownsSydney, sRevDownsSydney, sRevUpsSydney, SydneyUpDepth, SydneyDownDepth,
  370. SydneyRevUpWr, SydneyRevDownWr, SydneyRevUpMagnitude, SydneyRevDownMagnitude]
  371. = sessionReversalBt(wickUpSydney, wickDownSydney, engulfUpSydney, engulfDownSydney, recentSydneyClose, recentSydneyHigh, recentSydneyLow, sydney)
  372.  
  373. [revUpsTokyo, revDownsTokyo, sRevDownsTokyo, sRevUpsTokyo, TokyoUpDepth, TokyoDownDepth,
  374. TokyoRevUpWr, TokyoRevDownWr, TokyoRevUpMagnitude, TokyoRevDownMagnitude]
  375. = sessionReversalBt(wickUpTokyo, wickDownTokyo, engulfUpTokyo, engulfDownTokyo, recentTokyoClose, recentTokyoHigh, recentTokyoLow, tokyo)
  376.  
  377.  
  378. // Plot related calculations
  379.  
  380. //Current timeframe
  381. currentTf = timeframe.in_seconds(timeframe.period) / 60
  382.  
  383. //Note users when timeframe is above 1H and possibly not matching with selected session time periods
  384. tfNotification = currentTf > 60 and i_hideNotification == false ? "(!) Make sure timeframe supports selected session time periods. By default 1H is recommended." : ""
  385.  
  386. //Session candle colors
  387. londonColor = recentLondonClose > recentLondonClose[1] ? i_londonColUp : i_londonColDown
  388. nyColor = recentNyClose > recentNyOpen ? i_nyColUp : i_nyColDown
  389. sydneyColor = recentSydneyClose > recentSydneyClose[1] ? i_sydneyColUp : i_sydneyColDown
  390. tokyoColor = recentTokyoClose > recentTokyoClose[1] ? i_tokyoColUp : i_tokyoColDown
  391.  
  392. //MA color, using "switch" method to avoid incorrect colors when MA value is equal to last MA value (happens on lower timeframes)
  393. var color maCol = color.gray
  394.  
  395. if hybridSma > hybridSma[1]
  396. maCol := i_maColUp
  397.  
  398. if hybridSma == hybridSma[1]
  399. maCol := maCol[1]
  400.  
  401. if hybridSma < hybridSma[1]
  402. maCol := i_maColDown
  403.  
  404. //Session candle visuals
  405. borderWidth = 0
  406. linewidth = 2
  407.  
  408. //Session reversal colors
  409.  
  410. //Any session reversal
  411. anyWickUp = wickUpNy or wickUpLondon or wickUpSydney or wickUpTokyo
  412. anyWickDown = wickDownNy or wickDownLondon or wickDownSydney or wickDownTokyo
  413. anyEngulfUp = engulfUpNy or engulfUpLondon or engulfUpSydney or engulfUpTokyo
  414. anyEngulfDown = engulfDownNy or engulfDownLondon or engulfDownSydney or engulfDownTokyo
  415.  
  416. //Session reversal color
  417. revCol = anyWickUp ? color.green : anyWickDown ? color.red : anyEngulfUp ? color.teal : anyEngulfDown ? color.maroon : na
  418.  
  419. //Reversal number/text. Use LNST by default, 1-4 if numerized sessions is on.
  420. session1Text = i_numberedSessions ? "1" : "L"
  421. session2Text = i_numberedSessions ? "2" : "N"
  422. session3Text = i_numberedSessions ? "3" : "S"
  423. session4Text = i_numberedSessions ? "4" : "T"
  424.  
  425. //Reversal label texts
  426. revUpL = "▲" + "\n" + session1Text
  427. revDownL = session1Text + "\n" + "▼"
  428.  
  429. revUpN = "▲" + "\n" + session2Text
  430. revDownN = session2Text + "\n" + "▼"
  431.  
  432. revUpS = "▲" + "\n" + session3Text
  433. revDownS = session3Text + "\n" + "▼"
  434.  
  435. revUpT = "▲" + "\n" + session4Text
  436. revDownT = session4Text + "\n" + "▼"
  437.  
  438. //Highest session reversal up win rate
  439. highestWrUp = LondonRevUpWr >= NyRevUpWr and LondonRevUpWr >= SydneyRevUpWr and LondonRevUpWr >= TokyoRevUpWr ? 1 :
  440. NyRevUpWr >= LondonRevUpWr and NyRevUpWr >= SydneyRevUpWr and NyRevUpWr >= TokyoRevUpWr ? 2 :
  441. SydneyRevUpWr >= LondonRevUpWr and SydneyRevUpWr >= NyRevUpWr and SydneyRevUpWr >= TokyoRevUpWr ? 3 : 4
  442.  
  443. //Highest session reversal down win rate
  444. highestWrDown = LondonRevDownWr >= NyRevDownWr and LondonRevDownWr >= SydneyRevDownWr and LondonRevDownWr >= TokyoRevDownWr ? 1 :
  445. NyRevDownWr >= LondonRevDownWr and NyRevDownWr >= SydneyRevDownWr and NyRevDownWr >= TokyoRevDownWr ? 2 :
  446. SydneyRevDownWr >= LondonRevDownWr and SydneyRevDownWr >= NyRevDownWr and SydneyRevDownWr >= TokyoRevDownWr ? 3 : 4
  447.  
  448. //Highest session magnitude up
  449. highestMagnitudeUp = LondonRevUpMagnitude >= NyRevUpMagnitude and LondonRevUpMagnitude >= SydneyRevUpMagnitude and LondonRevUpMagnitude >= TokyoRevUpMagnitude ? 1 :
  450. NyRevUpMagnitude >= LondonRevUpMagnitude and NyRevUpMagnitude >= SydneyRevUpMagnitude and NyRevUpMagnitude >= TokyoRevUpMagnitude ? 2 :
  451. SydneyRevUpMagnitude >= LondonRevUpMagnitude and SydneyRevUpMagnitude >= NyRevUpMagnitude and SydneyRevUpMagnitude >= TokyoRevUpMagnitude ? 3 : 4
  452.  
  453. //Highest session magnitude down
  454. highestMagnitudeDown = LondonRevDownMagnitude <= NyRevDownMagnitude and LondonRevDownMagnitude <= SydneyRevDownMagnitude and LondonRevDownMagnitude <= TokyoRevDownMagnitude ? 1 :
  455. NyRevDownMagnitude <= LondonRevDownMagnitude and NyRevDownMagnitude <= SydneyRevDownMagnitude and NyRevDownMagnitude <= TokyoRevDownMagnitude ? 2 :
  456. SydneyRevDownMagnitude <= LondonRevDownMagnitude and SydneyRevDownMagnitude <= NyRevDownMagnitude and SydneyRevDownMagnitude <= TokyoRevDownMagnitude ? 3 : 4
  457.  
  458. //Reversal backtest table texts. Add 🔸 if given session reversal backtest metric is best perofrming
  459. revUpLText = session1Text + " ▲ : " + str.tostring(revUpsLondon) + " | " + "WR: " + str.tostring(LondonRevUpWr) + "%" + (highestWrUp == 1 ? " 🔸" : "") + " | " + "M: " + str.tostring(LondonRevUpMagnitude) + "%" + (highestMagnitudeUp == 1 ? " 🔸" : "")
  460. revDownLText = session1Text + " ▼ : " + str.tostring(revDownsLondon) + " | " + "WR: " + str.tostring(LondonRevDownWr) + "%" + (highestWrDown == 1 ? " 🔸" : "") + " | " + " M: " + str.tostring(LondonRevDownMagnitude) + "%" + (highestMagnitudeDown == 1 ? " 🔸" : "")
  461.  
  462. revUpNText = session2Text + " ▲ : " + str.tostring(revUpsNy) + " | " + "WR: " + str.tostring(NyRevUpWr) + "%" + (highestWrUp == 2 ? " 🔸" : "") + " | " + "M: " + str.tostring(NyRevUpMagnitude) + "%" + (highestMagnitudeUp == 2 ? " 🔸" : "")
  463. revDownNText = session2Text + " ▼ : " + str.tostring(revDownsNy) + " | " + "WR: " + str.tostring(NyRevDownWr) + "%" + (highestWrDown == 2 ? " 🔸" : "") + " | " + " M: " + str.tostring(NyRevDownMagnitude) + "%" + (highestMagnitudeDown == 2 ? " 🔸" : "")
  464.  
  465. revUpSText = session3Text + " ▲ : " + str.tostring(revUpsSydney) + " | " + "WR: " + str.tostring(SydneyRevUpWr) + "%" + (highestWrUp == 3 ? " 🔸" : "") + " | " + "M: " + str.tostring(SydneyRevUpMagnitude) + "%" + (highestMagnitudeUp == 3 ? " 🔸" : "")
  466. revDownSText = session3Text + " ▼ : " + str.tostring(revDownsSydney) + " | " + "WR: " + str.tostring(SydneyRevDownWr) + "%" + (highestWrDown == 3 ? " 🔸" : "") + " | " + " M: " + str.tostring(SydneyRevDownMagnitude) + "%" + (highestMagnitudeDown == 3 ? " 🔸" : "")
  467.  
  468. revUpTText = session4Text + " ▲ : " + str.tostring(revUpsTokyo) + " | " + "WR: " + str.tostring(TokyoRevUpWr) + "%" + (highestWrUp == 4 ? " 🔸" : "") + " | " + "M: " + str.tostring(TokyoRevUpMagnitude) + "%" + (highestMagnitudeUp == 4 ? " 🔸" : "")
  469. revDownTText = session4Text + " ▼ : " + str.tostring(revDownsTokyo) + " | " + "WR: " + str.tostring(TokyoRevDownWr) + "%" + (highestWrDown == 4 ? " 🔸" : "") + " | " + " M: " + str.tostring(TokyoRevDownMagnitude) + "%" + (highestMagnitudeDown == 4 ? " 🔸" : "")
  470.  
  471. //Function for forming session candles using line and box, available for first 500 bars. Clear look. Forming session reversal labels also.
  472. sessionCandles(session, sessionOffset, sessionOpen, sessionHigh, sessionLow, sessionClose, sessionWickUp, sessionEngUp, sessionWickDown, sessionEngDown, sessionCol, revUpText, revDownText) =>
  473.  
  474. //Session candles
  475. if sessionEnd(session)[1]
  476. line.new(bar_index + sessionOffset, sessionHigh, bar_index + sessionOffset, sessionLow, xloc=xloc.bar_index, color=sessionCol, width=linewidth, style=line.style_solid)
  477. box.new(left=bar_index - 1 + sessionOffset, top=sessionClose, right=bar_index + 1 + sessionOffset, bottom=sessionOpen, bgcolor=sessionCol, border_color=color.new(color.white, 100), border_width=borderWidth)
  478.  
  479. //Session reversals
  480. if (sessionWickUp or sessionEngUp) and sessionEnd(session)[1] and barstate.isconfirmed
  481. label.new(x=bar_index + sessionOffset, y=sessionLow, xloc=xloc.bar_index, yloc=yloc.price, text=revUpText, style=label.style_label_up, textcolor=color.new(revCol, 1), color=color.new(color.green, 100), size=size.normal)
  482.  
  483. if (sessionWickDown or sessionEngDown) and sessionEnd(session)[1] and barstate.isconfirmed
  484. label.new(x=bar_index + sessionOffset, y=sessionHigh, xloc=xloc.bar_index, yloc=yloc.price, text=revDownText, style=label.style_label_down, textcolor=color.new(revCol, 1), color=color.new(color.red, 100), size=size.normal)
  485.  
  486. //Function for forming session candles using plotcandle() function, available for all bars. Not so clear, but goes back indefinitely.
  487. sessionCandles2(session, sessionOffset, showSession, sessionOpen, sessionHigh, sessionLow, sessionClose) =>
  488.  
  489. //Session OHLC values with offset for plotcandle() function
  490. sessionEndO = ta.barssince(sessionEnd(session)) == 1 + sessionOffset and showSession ? sessionOpen : na
  491. sessionEndH = ta.barssince(sessionEnd(session)) == 1 + sessionOffset and showSession ? sessionHigh : na
  492. sessionEndL = ta.barssince(sessionEnd(session)) == 1 + sessionOffset and showSession ? sessionLow : na
  493. sessionEndC = ta.barssince(sessionEnd(session)) == 1 + sessionOffset and showSession ? sessionClose : na
  494.  
  495. [sessionEndO, sessionEndH, sessionEndL, sessionEndC]
  496.  
  497. //Function for forming backtest visuals.
  498. sessionReversalBtVisuals(session, sessionHigh, sessionLow, sessionClose, succesfulRevsUp, succesfulRevsDown, revsUp, revsDown, revUpWr, revUpMagnitude, revDownWr, revDownMagnitude, sessionOffset) =>
  499.  
  500. //Get bar_index space between session reversals
  501. btPeriod = ta.valuewhen(sessionEnd(session), bar_index, 0) - ta.valuewhen(sessionEnd(session), bar_index, 1)
  502.  
  503. //Reversal up texts
  504. sRevUpMagnitudeText = " Gain: +" + str.tostring(math.round((sessionHigh / sessionClose[1]) - 1, 4) * 100) + "%" + "\n" + "◣ Avg: +" + str.tostring(revUpMagnitude) + "%"
  505. sRevUpWrText = "\n" + "\n" + "\n" + "Succesful: " + str.tostring(succesfulRevsUp) + "\n" + "Win rate: " + str.tostring(revUpWr) + "%"
  506. revUpCountText = "\n" + "\n" + "Count: " + str.tostring(revsUp)
  507.  
  508. //Reversal down texts
  509. sRevDownMagnitudeText = "◤ Gain: " + str.tostring(math.round((sessionLow / sessionClose[1]) - 1, 4) * 100) + "%" + "\n" + " Avg: " + str.tostring(revDownMagnitude) + "%"
  510. sRevDownWrText = "Succesful: " + str.tostring(succesfulRevsDown) + "\n" + "Win rate: " + str.tostring(revDownWr) + "%" + "\n" + "\n" + "\n"
  511. revDownCountText = "Count: " + str.tostring(revsDown) + "\n" + "\n"
  512.  
  513. //If reversal is succesful and session ended 1 period ago, plot line and labels
  514. if succesfulRevsUp > succesfulRevsUp[1] and sessionEnd(session)[1]
  515. line.new(bar_index[btPeriod] + sessionOffset, sessionClose[1], bar_index + sessionOffset, sessionHigh, xloc=xloc.bar_index, color=color.white, width=1, style=line.style_solid)
  516. label.new(x=bar_index + sessionOffset, y=sessionHigh, xloc=xloc.bar_index, yloc=yloc.price, text=sRevUpMagnitudeText, style=label.style_label_lower_left, textcolor=color.new(color.white, 1), color=color.new(color.green, 100), size=size.normal)
  517. label.new(x=bar_index[btPeriod] + sessionOffset, y=sessionLow[btPeriod], xloc=xloc.bar_index, yloc=yloc.price, text=sRevUpWrText, style=label.style_label_up, textcolor=color.new(color.white, 1), color=color.new(color.green, 100), size=size.normal)
  518.  
  519. //If reversal occurs, plot label
  520. if revsUp > revsUp[1]
  521. label.new(x=bar_index + sessionOffset, y=sessionLow, xloc=xloc.bar_index, yloc=yloc.price, text=revUpCountText, style=label.style_label_up, textcolor=color.new(color.white, 1), color=color.new(color.green, 100), size=size.normal)
  522.  
  523. //If reversal is succesful and session ended 1 period ago, plot line and labels
  524. if succesfulRevsDown > succesfulRevsDown[1] and sessionEnd(session)[1]
  525. line.new(bar_index[btPeriod] + sessionOffset, sessionClose[1], bar_index + sessionOffset, sessionLow, xloc=xloc.bar_index, color=color.white, width=1, style=line.style_solid)
  526. label.new(x=bar_index + sessionOffset, y=sessionLow, xloc=xloc.bar_index, yloc=yloc.price, text=sRevDownMagnitudeText, style=label.style_label_upper_left, textcolor=color.new(color.white, 1), color=color.new(color.red, 100), size=size.normal)
  527. label.new(x=bar_index[btPeriod] + sessionOffset, y=sessionHigh[btPeriod], xloc=xloc.bar_index, yloc=yloc.price, text=sRevDownWrText, style=label.style_label_down, textcolor=color.new(color.white, 1), color=color.new(color.green, 100), size=size.normal)
  528.  
  529. //If reversal occurs, plot label
  530. if revsDown > revsDown[1]
  531. label.new(x=bar_index + sessionOffset, y=sessionHigh, xloc=xloc.bar_index, yloc=yloc.price, text=revDownCountText, style=label.style_label_down, textcolor=color.new(color.white, 1), color=color.new(color.green, 100), size=size.normal)
  532.  
  533. //Session candles using line and box
  534. londonCandles = show_london ? sessionCandles(london, i_londonOffset, recentLondonOpen, recentLondonHigh, recentLondonLow, recentLondonClose, wickUpLondon, engulfUpLondon, wickDownLondon, engulfDownLondon, londonColor, revUpL, revDownL) : na
  535. nyCandles = show_ny ? sessionCandles(ny, i_nyOffset, recentNyOpen, recentNyHigh, recentNyLow, recentNyClose, wickUpNy, engulfUpNy, wickDownNy, engulfDownNy, nyColor, revUpN, revDownN) : na
  536. sydneyCandles = show_sydney ? sessionCandles(sydney, i_sydneyOffset, recentSydneyOpen, recentSydneyHigh, recentSydneyLow, recentSydneyClose, wickUpSydney, engulfUpSydney, wickDownSydney, engulfDownSydney, sydneyColor, revUpS, revDownS) : na
  537. tokyoCandles = show_tokyo ? sessionCandles(tokyo, i_tokyoOffset, recentTokyoOpen, recentTokyoHigh, recentTokyoLow, recentTokyoClose, wickUpTokyo, engulfUpTokyo, wickDownTokyo, engulfDownTokyo, tokyoColor, revUpT, revDownT) : na
  538.  
  539. //Session candles using plotcandle()
  540. [sessionEndLondonO, sessionEndLondonH, sessionEndLondonL, sessionEndLondonC] = sessionCandles2(london, i_londonOffset, show_london, recentLondonOpen, recentLondonHigh, recentLondonLow, recentLondonClose)
  541. [sessionEndNyO, sessionEndNyH, sessionEndNyL, sessionEndNyC] = sessionCandles2(ny, i_nyOffset, show_ny, recentNyOpen, recentNyHigh, recentNyLow, recentNyClose)
  542. [sessionEndSydneyO, sessionEndSydneyH, sessionEndSydneyL, sessionEndSydneyC] = sessionCandles2(sydney, i_sydneyOffset, show_sydney, recentSydneyOpen, recentSydneyHigh, recentSydneyLow, recentSydneyClose)
  543. [sessionEndTokyoO, sessionEndTokyoH, sessionEndTokyoL, sessionEndTokyoC] = sessionCandles2(tokyo, i_tokyoOffset, show_tokyo, recentTokyoOpen, recentTokyoHigh, recentTokyoLow, recentTokyoClose)
  544.  
  545. //Session reversal backtest visuals
  546. londonBtVisuals = i_highlightBt == "Session #1" and show_london ?
  547. sessionReversalBtVisuals(london, recentLondonHigh, recentLondonLow, recentLondonClose, sRevUpsLondon, sRevDownsLondon, revUpsLondon, revDownsLondon, LondonRevUpWr, LondonRevUpMagnitude, LondonRevDownWr, LondonRevDownMagnitude, i_londonOffset) : na
  548.  
  549. nyBtVisuals = i_highlightBt == "Session #2" and show_ny ?
  550. sessionReversalBtVisuals(ny, recentNyHigh, recentNyLow, recentNyClose, sRevUpsNy, sRevDownsNy, revUpsNy, revDownsNy, NyRevUpWr, NyRevUpMagnitude, NyRevDownWr, NyRevDownMagnitude, i_nyOffset) : na
  551.  
  552. sydneyBtVisuals = i_highlightBt == "Session #3" and show_sydney ?
  553. sessionReversalBtVisuals(sydney, recentSydneyHigh, recentSydneyLow, recentSydneyClose, sRevUpsSydney, sRevDownsSydney, revUpsSydney, revDownsSydney, SydneyRevUpWr, SydneyRevUpMagnitude, SydneyRevDownWr, SydneyRevDownMagnitude, i_sydneyOffset) : na
  554.  
  555. tokyoBtVisuals = i_highlightBt == "Session #4" and show_tokyo ?
  556. sessionReversalBtVisuals(tokyo, recentTokyoHigh, recentTokyoLow, recentTokyoClose, sRevUpsTokyo, sRevDownsTokyo, revUpsTokyo, revDownsTokyo, TokyoRevUpWr, TokyoRevUpMagnitude, TokyoRevDownWr, TokyoRevDownMagnitude, i_tokyoOffset) : na
  557.  
  558.  
  559. // Plots
  560.  
  561. //MA
  562. plot(hybridSma, color=maCol, title="Session moving average")
  563.  
  564. //Regular session candle using plotcandle() function.
  565. plotcandle(sessionEndLondonO, sessionEndLondonH, sessionEndLondonL, sessionEndLondonC, color=londonColor)
  566. plotcandle(sessionEndNyO, sessionEndNyH, sessionEndNyL, sessionEndNyC, color=nyColor)
  567. plotcandle(sessionEndSydneyO, sessionEndSydneyH, sessionEndSydneyL, sessionEndSydneyC, color=sydneyColor)
  568. plotcandle(sessionEndTokyoO, sessionEndTokyoH, sessionEndTokyoL, sessionEndTokyoC, color=tokyoColor)
  569.  
  570. //Session period background highlights
  571. bgcolor(i_highlightSession == true and show_london == true and sessionOn(london) ? color.new(i_londonColSession, 90) : na)
  572. bgcolor(i_highlightSession == true and show_london == true and sessionStart(london) ? color.new(i_londonColSession, 50) : na)
  573. bgcolor(i_highlightSession == true and show_london == true and sessionEnd(london) ? color.new(i_londonColSession, 50) : na)
  574.  
  575. bgcolor(i_highlightSession == true and show_ny == true and sessionOn(ny) ? color.new(i_nyColSession, 90) : na)
  576. bgcolor(i_highlightSession == true and show_ny == true and sessionStart(ny) ? color.new(i_nyColSession, 50) : na)
  577. bgcolor(i_highlightSession == true and show_ny == true and sessionEnd(ny) ? color.new(i_nyColSession, 50) : na)
  578.  
  579. bgcolor(i_highlightSession == true and show_sydney == true and sessionOn(sydney) ? color.new(i_sydneyColSession, 90) : na)
  580. bgcolor(i_highlightSession == true and show_sydney == true and sessionStart(sydney) ? color.new(i_sydneyColSession, 50) : na)
  581. bgcolor(i_highlightSession == true and show_sydney == true and sessionEnd(sydney) ? color.new(i_sydneyColSession, 50) : na)
  582.  
  583. bgcolor(i_highlightSession == true and show_tokyo == true and sessionOn(tokyo) ? color.new(i_tokyoColSession, 90) : na)
  584. bgcolor(i_highlightSession == true and show_tokyo == true and sessionStart(tokyo) ? color.new(i_tokyoColSession, 50) : na)
  585. bgcolor(i_highlightSession == true and show_tokyo == true and sessionEnd(tokyo) ? color.new(i_tokyoColSession, 50) : na)
  586.  
  587. //Hide chart
  588. barcolor(i_hideChart == true ? color.new(color.white, 100) : na)
  589.  
  590.  
  591. // Alerts
  592.  
  593. //Confirmed session candle closes
  594. alertcondition(sessionEnd(london)[1], "Confirmed session #1 candle close", "Confirmed session #1 candle close detected")
  595. alertcondition(sessionEnd(ny)[1], "Confirmed session #2 candle close", "Confirmed session #2 candle close detected")
  596. alertcondition(sessionEnd(sydney)[1], "Confirmed session #3 candle close", "Confirmed session #3 candle close detected")
  597. alertcondition(sessionEnd(tokyo)[1], "Confirmed session #4 candle close", "Confirmed session #4 candle close detected")
  598.  
  599. //Confirmed any session candle close
  600. anySessionClose = sessionEnd(london)[1] or sessionEnd(ny)[1] or sessionEnd(sydney)[1] or sessionEnd(tokyo)[1]
  601. alertcondition(anySessionClose, "Confirmed session (any) candle close", "Confirmed session (any) candle close detected")
  602.  
  603. //Confirmed session reversals up
  604. alertcondition(revUpsLondon > revUpsLondon[1], "Confirmed session #1 reversal up", "Confirmed session #1 reversal up detected")
  605. alertcondition(revUpsNy > revUpsNy[1], "Confirmed session #2 reversal up", "Confirmed session #2 reversal up detected")
  606. alertcondition(revUpsSydney > revUpsSydney[1], "Confirmed session #3 reversal up", "Confirmed session #3 reversal up detected")
  607. alertcondition(revUpsTokyo > revUpsTokyo[1], "Confirmed session #4 reversal up", "Confirmed session #4 reversal up detected")
  608.  
  609. //Confirmed any session reversal up
  610. anySessionRevUp = revUpsLondon > revUpsLondon[1] or revUpsNy > revUpsNy[1] or revUpsSydney > revUpsSydney[1] or revUpsTokyo > revUpsTokyo[1]
  611. alertcondition(anySessionRevUp, "Confirmed session (any) reversal up", "Confirmed session (any) reversal up detected")
  612.  
  613. //Confirmed session reversals down
  614. alertcondition(revDownsLondon > revDownsLondon[1], "Confirmed session #1 reversal down", "Confirmed session #1 reversal down detected")
  615. alertcondition(revDownsNy > revDownsNy[1], "Confirmed session #2 reversal down", "Confirmed session #2 reversal down detected")
  616. alertcondition(revDownsSydney > revDownsSydney[1], "Confirmed session #3 reversal down", "Confirmed session #3 reversal down detected")
  617. alertcondition(revDownsTokyo > revDownsTokyo[1], "Confirmed session #4 reversal down", "Confirmed session #4 reversal down detected")
  618.  
  619. //Confirmed any session reversal down
  620. anySessionRevDown = revDownsLondon > revDownsLondon[1] or revDownsNy > revDownsNy[1] or revDownsSydney > revDownsSydney[1] or revDownsTokyo > revDownsTokyo[1]
  621. alertcondition(anySessionRevDown, "Confirmed session (any) candle reversal down", "Confirmed session (any) reversal down detected")
  622.  
  623. //Confirmed any session reversal up/down
  624. alertcondition(anySessionRevDown or anySessionRevUp, "Confirmed session (any) reversal up/down", "Confirmed session (any) reversal up/down detected")
  625.  
  626.  
  627. // Backtest table
  628.  
  629. //Initialize backtest table and timeframe notification table
  630. var activeTable = table.new(position = position.top_right, columns = 50, rows = 50, bgcolor = color.rgb(29, 29, 29), border_width = 3, border_color = color.new(color.white, 100))
  631. var notifyTable = table.new(position = position.bottom_right, columns = 50, rows = 50, bgcolor = color.new(color.white, 100), border_width = 3)
  632.  
  633. //Populate backtest table cells
  634. table.cell(table_id = activeTable, column = 0, row = 0, text = revUpLText + "\n" + "⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯" + "\n" + revDownLText, bgcolor=color.rgb(48, 48, 48), text_color = color.white)
  635. table.cell(table_id = activeTable, column = 1, row = 0, text = revUpNText + "\n" + "⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯" + "\n" + revDownNText, bgcolor=color.rgb(48, 48, 48), text_color = color.white)
  636. table.cell(table_id = activeTable, column = 0, row = 2, text = revUpSText + "\n" + "⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯" + "\n" + revDownSText, bgcolor=color.rgb(48, 48, 48), text_color = color.white)
  637. table.cell(table_id = activeTable, column = 1, row = 2, text = revUpTText + "\n" + "⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯" + "\n" + revDownTText, bgcolor=color.rgb(48, 48, 48), text_color = color.white)
  638.  
  639. //Populate timeframe notification table if applicable
  640. table.cell(table_id = notifyTable, column = 0, row = 0, text = "" + tfNotification, text_color=color.yellow, bgcolor = color.new(color.white, 100))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement