RM Timeframe Continuity
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © millerrh

//@version=5
// Revision 1
// This indicator identifies timeframe continuity (per Strat) in multiple higher timeframes and shows them in a widget off to the right of the chart.
// It's meant to be used as an alternative filter for "trading with the trend." Typically people use moving averages of varying lengths for this
// (i.e. if over 200 MA it's an uptrend, etc.)
// For the purposes of this indicator, it looks at the following conditions on different timeframes: Green/Red Candles, Inside Bars, Outside Bars, and 
// Continuation Bars. For timeframe continuity, you want to trade in the direction where all timeframes are aligned.  Inside bars can be good indicators
// of potentail breakout opportunities.

indicator('RM Timeframe Continuity', overlay=true)

// == USER INPUTS ==
tableLocation = input.string(defval='Top', options=['Top', 'Bottom'], title='Info Table Location', group='Display', 
  tooltip='Place information table on the top of the pane or the bottom of the pane.')
oneSet = input.timeframe(defval='240', title='First Timeframe', group='Higher Timeframe Levels', 
  tooltip='Allows you to set different time frames for timeframe continuity.')
twoSet = input.timeframe(defval='D', title='Second Timeframe', group='Higher Timeframe Levels')
threeSet = input.timeframe(defval='W', title='Third Timeframe', group='Higher Timeframe Levels')
fourSet = input.timeframe(defval='M', title='Fourth Timeframe', group='Higher Timeframe Levels')
showMTFLevels = input.bool(title='Show Multiple Timeframe S/R Levels?', defval=true, group='Higher Timeframe Levels', 
  tooltip='Displays the highs and lows of higher timeframes to use as support/resistance levels. When these levels break, 
  the continuity will change relative to these higher timeframes.')
oneColorS = input.color(color.new(color.orange, 50), title='1st Timeframe    Support', group='Higher Timeframe Levels', inline='MTF1')
oneColorR = input.color(color.new(color.orange, 50), title=' Resistance', group='Higher Timeframe Levels', inline='MTF1')
twoColorS = input.color(color.new(color.blue, 50), title='2nd Timeframe   Support', group='Higher Timeframe Levels', inline='MTF2')
twoColorR = input.color(color.new(color.blue, 50), title=' Resistance', group='Higher Timeframe Levels', inline='MTF2')
threeColorS = input.color(color.new(color.purple, 50), title='3rd Timeframe    Support', group='Higher Timeframe Levels', inline='MTF3')
threeColorR = input.color(color.new(color.purple, 50), title=' Resistance', group='Higher Timeframe Levels', inline='MTF3')
fourColorS = input.color(color.new(color.white, 50), title='4th Timeframe    Support', group='Higher Timeframe Levels', inline='MTF4')
fourColorR = input.color(color.new(color.white, 50), title=' Resistance', group='Higher Timeframe Levels', inline='MTF4')

//  == DEFINE FUNCTIONS FOR USE IN MULTIPLE TIMEFRAMES (USING A TUPLE TO AVOID SO MANY SECURITY CALLS) ==  
f_Strat() =>
    green = close >= open
    red = close < open
    one = (high <= high[1]) and (low >= low[1])
    twoUp = (high > high[1]) and (low >= low[1])
    twoDown = (high <= high[1]) and (low < low[1])
    three = (high > high[1]) and (low < low[1])
    openTime = time
    lowPrice = low
    highPrice = high
    [green, red, one, twoUp, twoDown, three, openTime, lowPrice, highPrice]

[green_1, red_1, one_1, twoUp_1, twoDown_1, three_1, openTime_1, lowPrice_1, highPrice_1] = request.security(syminfo.tickerid, oneSet, f_Strat())
[green_2, red_2, one_2, twoUp_2, twoDown_2, three_2, openTime_2, lowPrice_2, highPrice_2] = request.security(syminfo.tickerid, twoSet, f_Strat())
[green_3, red_3, one_3, twoUp_3, twoDown_3, three_3, openTime_3, lowPrice_3, highPrice_3] = request.security(syminfo.tickerid, threeSet, f_Strat())
[green_4, red_4, one_4, twoUp_4, twoDown_4, three_4, openTime_4, lowPrice_4, highPrice_4] = request.security(syminfo.tickerid, fourSet, f_Strat())

// == PLOT SUPPORT/RESISTANCE LINES OF THE HIGHER TIMEFRAMES ==
// Use a function to define the lines
f_line(x1, y1, y2, _color) =>
    var line id = na
    line.delete(id)
    id := line.new(x1, y1, time, y2, xloc.bar_time, extend.right, _color)
    id

// 1st Timeframe
highLine1 = showMTFLevels ? f_line(openTime_1, highPrice_1, highPrice_1, oneColorR) : na
lowLine1 = showMTFLevels ? f_line(openTime_1, lowPrice_1, lowPrice_1, oneColorS) : na
// 2nd Timeframe
highLine2 = showMTFLevels ? f_line(openTime_2, highPrice_2, highPrice_2, twoColorR) : na
lowLine2 = showMTFLevels ? f_line(openTime_2, lowPrice_2, lowPrice_2, twoColorS) : na
// 3rd Timeframe
highLine3 = showMTFLevels ? f_line(openTime_3, highPrice_3, highPrice_3, threeColorR) : na
lowLine3 = showMTFLevels ? f_line(openTime_3, lowPrice_3, lowPrice_3, threeColorS) : na
// 4th Timeframe
highLine4 = showMTFLevels ? f_line(openTime_4, highPrice_4, highPrice_4, fourColorR) : na
lowLine4 = showMTFLevels ? f_line(openTime_4, lowPrice_4, lowPrice_4, fourColorS) : na


// == TABLE PLOTTING ==
tablePos = tableLocation == 'Top' ? position.top_right : position.bottom_right
var table trendTable = table.new(tablePos, 4, 1, border_width=3)
upColor = color.rgb(38, 166, 154)
downColor = color.rgb(240, 83, 80)
tfColor = color.new(#999999, 0)

// Check to ensure boxes are all higher timeframe than the chart to remove glyph and gray out box if that's the case
tfInMinutes(simple string tf = "") =>
    float chartTf =
      timeframe.multiplier * (
      timeframe.isseconds ? 1. / 60             :
      timeframe.isminutes ? 1.                  :
      timeframe.isdaily   ? 60. * 24            :
      timeframe.isweekly  ? 60. * 24 * 7        :
      timeframe.ismonthly ? 60. * 24 * 30.4375  : na)
    float result = tf == "" ? chartTf : request.security(syminfo.tickerid, tf, chartTf)
    
float chartTFInMinutes = tfInMinutes()
bool TF1Check = tfInMinutes(oneSet) < chartTFInMinutes
bool TF2Check = tfInMinutes(twoSet) < chartTFInMinutes
bool TF3Check = tfInMinutes(threeSet) < chartTFInMinutes
bool TF4Check = tfInMinutes(fourSet) < chartTFInMinutes

// Define glyphs
glyph1 = TF1Check ? na : one_1 ? '⬤  ': twoUp_1 ? '▲ ' : twoDown_1 ? '▼ ' : three_1 ? '▮ ': na
glyph2 = TF2Check ? na : one_2 ? '⬤  ': twoUp_2 ? '▲ ' : twoDown_2 ? '▼ ' : three_2 ? '▮ ': na
glyph3 = TF3Check ? na : one_3 ? '⬤  ': twoUp_3 ? '▲ ' : twoDown_3 ? '▼ ' : three_3 ? '▮ ': na
glyph4 = TF4Check ? na : one_4 ? '⬤  ': twoUp_4 ? '▲ ' : twoDown_4 ? '▼ ' : three_4 ? '▮ ': na

f_fillCell(_column, _row, _cellText, _c_color) =>
    table.cell(trendTable, _column, _row, _cellText, bgcolor=color.new(_c_color, 70), text_color=_c_color, width=5)

if barstate.islast
    f_fillCell(0, 0, glyph1 + oneSet, TF1Check ? tfColor : green_1 ? upColor : downColor)
    f_fillCell(1, 0, glyph2 + twoSet, TF2Check ? tfColor : green_2 ? upColor : downColor)
    f_fillCell(2, 0, glyph3 + threeSet, TF3Check ? tfColor : green_3 ? upColor : downColor)
    f_fillCell(3, 0, glyph4 + fourSet, TF4Check ? tfColor : green_4 ? upColor : downColor)

