Indicator Based Market Exposure (IBME)
// This source code is subject to the teratioMults of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Amphibiantrading

//@version=5
indicator('Indicator Based Market Exposure', shorttitle = 'IBME', overlay = true)

//---------inputs---------//
showRunTime     = input.bool(true, 'Show Time Frame Error', tooltip = 'The IBME signal is meant to be shown on a daily chart. Selecting this option will warn you if you are on a different time frame.')

var g0          = 'Display Options'
bgHighlight     = input.bool(true, 'Highlight Chart Background', group = g0)
bgColG          = input(color.rgb(76, 175, 80, 85), 'Background Color Green')
bgColY          = input(color.rgb(246, 191, 32, 85),'Background Color Yellow')
bgColR          = input(color.rgb(255, 82, 82, 85), 'Background Color Red')

var g1          = 'Table Options'
showTable       = input.bool(true, 'Show IBME Data Table', group = g1)
showSep         = input.bool(false, 'Show Individual Signals', group = g1)
yPos            = input.string('Top', 'Table Position ', options = ['Top', 'Middle', 'Bottom'], inline = '1',  group= g1)
xPos            = input.string('Right', ' ', options = ['Right','Center', 'Left'], inline = '1',  group = g1)
tableTextSize   = input.string('Normal', 'Text Size', options = ['Small','Normal','Large','Huge'], inline = '2', group = g1)
tableTextColor  = input.color(color.black, 'Text Color', inline = '2', group = g1)
tableBgColor    = input.color(color.white, 'Table Background Color', group = g1)

var g2          = 'MSI Settings'
advIssues       = input.symbol('ADVN', 'Advancing Stocks Symbol', group = g2)
decIssues       = input.symbol('DECN', 'Declining Stocks Symbol', group = g2)
isRA            = input.bool(true, 'Stockcharts version (Ratio Adjusted)?', group = g2)
ratioMult       = input.int(1000, 'RANA ratio multiplier', group = g2)
msiMaLen        = input.int(10, 'SMA  Length', group = g2)

var g3          = 'Net High / Lows Settings'
inas            = input.bool(true,'Nasdaq', inline = '1', group = g3)
inyse           = input.bool(false,'NYSE', inline = '1', group = g3)
nhlMaLen        = input.int(50, 'SMA Length', group = g3)

var g4          = 'Price Action Settings'
maSym           = input.symbol('QQQ', 'Moving Average Symbol', group = g4)
ma1len          = input.int(10, 'Fast MA', inline = '1', group = g4)
ma1Type         = input.string('SMA', ' ', options = ['EMA', 'SMA'], inline = '1', group = g4)
ma2len          = input.int(20, 'Fast MA', inline = '2', group = g4)
ma2Type         = input.string('SMA', ' ', options = ['EMA', 'SMA'], inline = '2', group = g4)

//----------functions & switch----------//
txtSize = switch tableTextSize
    'Small' => size.small
    'Normal' => size.normal
    'Large' => size.large
    'Huge' => size.huge

getArrayValue(arr, idx) =>
    if array.size(arr) > idx
        array.get(arr, idx)
    else
        na

//---------msi---------//
ai = request.security(advIssues, 'D', close) 
di = request.security(decIssues, 'D', close)

rana    = ratioMult * (ai-di)/(ai+di)
e1      = isRA ? ta.ema(rana, 19) : ta.ema(ai-di, 19)
e2      = isRA ? ta.ema(rana, 39) : ta.ema(ai-di, 39)
mo      = e1 - e2
msi     = 0.
msi     := nz(msi[1]) + mo
ma      = ta.sma(msi,msiMaLen)

greenMsi = msi > ma

//---------net high lows---------//
hq = request.security('HIGQ', 'D', close)
lq = request.security('LOWQ', 'D', close)
hn = request.security('HIGN', 'D', close)
ln = request.security('LOWN', 'D', close)

higq = inas ? hq : 0
lowq = inas ? lq : 0
hign = inyse ? hn : 0
lown = inyse ? ln : 0

nhighs      = hign + higq - lown - lowq
greenNhl    = nhighs > 0

nhlMA       = ta.sma(nhighs, nhlMaLen)
greenXover  = nhighs >= nhlMA

//---------moving averages---------//
ma1 = ma1Type == 'EMA' ? ta.ema(close,ma1len) : ta.sma(close,ma1len)
ma2 = ma2Type == 'EMA' ? ta.ema(close,ma2len) : ta.sma(close,ma2len)

symMa1 = request.security(maSym, 'D', ma1)
symMa2 = request.security(maSym, 'D', ma2)
symCl  = request.security(maSym, 'D', close)

stacked = symMa1 > symMa2 and symCl >= symMa1


//---------signals---------//
sig1    = greenMsi and greenNhl and greenXover and stacked 
sig2    = greenMsi and greenNhl and greenXover and not stacked
sig3    = greenMsi and greenNhl and not greenXover
sig4    = greenMsi and not greenNhl and greenXover 
sig5    = greenMsi and not greenNhl and not greenXover
sig6    = not greenMsi and greenNhl and greenXover
sig7    = not greenMsi and greenNhl and not greenXover and stacked
sig8    = not greenMsi and not greenNhl and greenXover and stacked
sig9    = not greenMsi and not greenNhl and not greenXover and stacked 
sig10   = not greenMsi and greenNhl and not greenXover and not stacked 
sig11   = not greenMsi and not greenNhl and greenXover and not stacked 
sig12   = not greenMsi and not greenNhl and not greenXover and not stacked 

green   = sig1
yellow  = sig2 or sig3 or sig4 or sig5 or sig6 or sig7 or sig8 or sig9
red     = sig10 or sig11 or sig12 
action  = green ? '🟢' : yellow ? '🟡' : '🔴'

txtMsi      = greenMsi ? 'Above MA' : 'Below MA'
txtNhl      = greenNhl ? 'Positive' : 'Negative'
txtXover    = greenXover ? 'Positive' : 'Negative'
txtMa       = stacked ? 'Yes' : 'No'
actionTxt   = green ? 'Full-Sized Longs' : yellow ? 'Pilot Positions' : 'No Longs'

signalArray = array.new<string>()
signalToolTip = ''

if sig1
    signalArray.push('#1')
if sig2
    signalArray.push('#2')
if sig3
    signalArray.push('#3')
if sig4
    signalArray.push('#4')
if sig5
    signalArray.push('#5')
if sig6
    signalArray.push('#6')
if sig7
    signalArray.push('#7')
if sig8
    signalArray.push('#8')
if sig9
    signalArray.push('#9')
if sig10
    signalArray.push('#10')
if sig11
    signalArray.push('#11')
if sig12
    signalArray.push('#12')

if signalArray.size() > 0
    for i = 0 to signalArray.size() - 1
        signalToolTip := signalToolTip + getArrayValue(signalArray, i)

//---------data table---------//
var table data = table.new(str.lower(yPos) + '_' + str.lower(xPos), 2, 8,color.new(color.white,100), 
     color.new(color.white,100), 2, color.new(color.white,100), 2)

if barstate.islast and timeframe.isdaily and showTable and yPos == 'Top'
    data.cell(0,0,'')
    data.merge_cells(0,0,1,0)
    data.cell(0,1, actionTxt + '  ' + signalToolTip, text_halign = text.align_center, bgcolor = tableBgColor, text_color = tableTextColor, text_size = txtSize)
    data.merge_cells(0,1,1,1)
    data.cell(0,2, 'IBME: ', text_halign = text.align_left, bgcolor = tableBgColor, text_size = txtSize, text_color = tableTextColor)
    data.cell(1,2, action, text_halign = text.align_center, bgcolor = tableBgColor, text_size = txtSize)
    if showSep
        data.cell(0,4,'Uptrend: ', text_halign = text.align_left, bgcolor = tableBgColor, text_color = tableTextColor, text_size = txtSize)
        data.cell(0,5, 'MSI: ', text_halign = text.align_left, bgcolor = tableBgColor, text_color = tableTextColor, text_size = txtSize)
        data.cell(0,6, 'NNHL: ', text_halign = text.align_left, bgcolor = tableBgColor, text_color = tableTextColor, text_size = txtSize)
        data.cell(0,7, 'NNHC: ', text_halign = text.align_left, bgcolor = tableBgColor, text_color = tableTextColor, text_size = txtSize)
        data.cell(1,4, txtMa, text_halign = text.align_center, bgcolor = tableBgColor, text_color = tableTextColor, text_size = txtSize)
        data.cell(1,5, txtMsi, text_halign = text.align_center, bgcolor = tableBgColor, text_color = tableTextColor, text_size = txtSize)
        data.cell(1,6, txtNhl, text_halign = text.align_center, bgcolor = tableBgColor, text_color = tableTextColor, text_size = txtSize)
        data.cell(1,7, txtXover, text_halign = text.align_center, bgcolor = tableBgColor, text_color = tableTextColor, text_size = txtSize)
else if barstate.islast and timeframe.isdaily and showTable
    data.cell(0,0, actionTxt + '  ' + signalToolTip, text_halign = text.align_center, bgcolor = tableBgColor, text_color = tableTextColor, text_size = txtSize)
    data.merge_cells(0,0,1,0)
    data.cell(0,1, 'IBME: ', text_halign = text.align_left, bgcolor = tableBgColor, text_size = txtSize, text_color = tableTextColor)
    data.cell(1,1, action, text_halign = text.align_center, bgcolor = tableBgColor, text_size = txtSize)
    if showSep
        data.cell(0,3,'Uptrend: ', text_halign = text.align_left, bgcolor = tableBgColor, text_color = tableTextColor, text_size = txtSize)
        data.cell(0,4, 'MSI: ', text_halign = text.align_left, bgcolor = tableBgColor, text_color = tableTextColor, text_size = txtSize)
        data.cell(0,5, 'NNHL: ', text_halign = text.align_left, bgcolor = tableBgColor, text_color = tableTextColor, text_size = txtSize)
        data.cell(0,6, 'NNHC: ', text_halign = text.align_left, bgcolor = tableBgColor, text_color = tableTextColor, text_size = txtSize)
        data.cell(1,3, txtMa, text_halign = text.align_center, bgcolor = tableBgColor, text_color = tableTextColor, text_size = txtSize)
        data.cell(1,4, txtMsi, text_halign = text.align_center, bgcolor = tableBgColor, text_color = tableTextColor, text_size = txtSize)
        data.cell(1,5, txtNhl, text_halign = text.align_center, bgcolor = tableBgColor, text_color = tableTextColor, text_size = txtSize)
        data.cell(1,6, txtXover, text_halign = text.align_center, bgcolor = tableBgColor, text_color = tableTextColor, text_size = txtSize)
else if not timeframe.isdaily and showRunTime
    runtime.error('Please switch to a daily time frame chart to see the IBME signal')

bgcolor(green and timeframe.isdaily and bgHighlight ? bgColG : na)
bgcolor(yellow and timeframe.isdaily and bgHighlight ? bgColY : na)
bgcolor(red and timeframe.isdaily and bgHighlight ? bgColR : na)

//----------alerts----------//
if green and not green[1]
    alert('IBME has turned green! Full-sized longs allowed', alert.freq_once_per_bar_close)
if yellow and not yellow[1]
    alert('IBME has turned yellow! Pilot positions permitted', alert.freq_once_per_bar_close)
if red and not red[1]
    alert('IBME has turned red! No new longs reccommended', alert.freq_once_per_bar_close)

