the Flasher
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © allanster

//@version=5
indicator("the Flasher", overlay = true)

// ⚠️ Seizure warning.
// WARNING: This indicator may potentially trigger seizures for people with photosensitive epilepsy. User discretion is advised.

warns = input.text_area('⚠️ Seizure warning.\n\nWARNING: This indicator may potentially trigger seizures for people with photosensitive epilepsy. User discretion is advised.')
agree = input.bool(false, 'Enable the Flasher')

// Briefly flashes chart background colors as a visual alert whenever a condition occurs, from the insatiable mind of @scarf.
// Special thanks to @LucF for his advice on improving efficiency of dynamic tables.

blipt = 'Persistent conditions that remain true will cycle only once. Transient conditions will cycle on each intrabar '    +
 'occurrence. Flashes for some transient conditions may be skipped if the color cycle for the previous condition has not '  +
 'concluded when the new condition occurs. If this is of concern then reducing the Cycles value lower will reduce the '     +
 'chance of overlapping cycles being skipped.\n\nCandles and other indicators may be obscured when colors are flashing if ' +
 'the mouse cursor is anywhere on the chart. Color cycling is dependent upon and only occurs upon feed updates.'
mssgt = 'Option to include flashed messages. Leave the Option field blank if no message is desired. Message colors are '    +
 'syncronized to occur with the corresponding color cycles that are set in the Cycles color settings.'
cntFt = 'Uncheck this box to disable the displaying of the current cycle number that is being flashed.'
blipU = input.int   (3,                      'Cycles', minval = 0,  inline = '1')
colU1 = input.color (color.new(#00ff00, 0),  '',                    inline = '1')
colU2 = input.color (color.new(#673ab7, 0),  '',                    inline = '1', tooltip = blipt)
mssgU = input.string('MA CROSSED UP!',       'Option',              inline = '2')
colu1 = input.color (color.new(#000000, 0),  '',                    inline = '2')
colu2 = input.color (color.new(#ffffff, 0),  '',                    inline = '2', tooltip = mssgt)
blipD = input.int   (3,                      'Cycles', minval = 0,  inline = '3')
colD1 = input.color (color.new(#ff0000, 0),  '',                    inline = '3')
colD2 = input.color (color.new(#ffff00, 0),  '',                    inline = '3', tooltip = blipt)
mssgD = input.string('MA CROSSED DN!',       'Option',              inline = '4')
cold1 = input.color (color.new(#ffffff, 0),  '',                    inline = '4')
cold2 = input.color (color.new(#000000, 0),  '',                    inline = '4', tooltip = mssgt)
cntFl = input       (true,                   'Show Cycles Counter',               tooltip = cntFt)

// This is "the Flasher" function.
flash(_agree, _tblNo, _condition, _blips, _colb1, _colb2, _string, _count, _cols1, _cols2) =>  //{
    tblNo = switch _tblNo
        1 => position.top_center
        => position.bottom_center                                               // declare position of tabLe instances
    var   tabLe = table.new(tblNo, 1, 1, color(na))                             // create tabLe instance
    table.cell(tabLe, 0, 0, "", 100, 100, #000000,
     text.align_center, text.align_top, size.huge)                              // define and set attributes for tabLe cell
    varip ticks = 0                                                             // declare intrabar count of price/volume updates
    varip state = _condition                                                    // declare intrabar value of _condition
    varip blink = false                                                         // declare intrabar monitor of change in _condition
    varip store = _condition                                                    // declare intrabar store of value of first _condition
    varip cycle = 0                                                             // declare intrabar cycle toggle for colors 1 & 2
    if _agree and barstate.isrealtime and _blips > 0                            // true for duration of realtime bars, _blips is the total allowed number of color flashes
        blink := _condition != state ? true : blink                             // once a change of _condition is true blink remains true, a persistent _condition is never true
        renew  = _condition and _condition != state                             // a new transient condition has occurred
        state := _condition                                                     // update intrabar value of _condition
        store := _condition ? true : store                                      // once first occurrence of _condition is true store remains true
        reset  = blink ? renew and ticks > _blips : false                       // reset flag if transient condition refires and number of _blips is met for previous transient _condition
        ticks := reset ? 1 : ticks + 1                                          // tick counter resets after _blips is met for transient _condition, else increments on price update
        cycle := reset ? 0 : cycle                                              // cycle resets to first color after flashes is met for intrabar _condition, else continues current cycle
        nFlsh  = _count ? '\nFlashes: ' + str.tostring(ticks) : ''              // display number of flashes
        if store and ticks <= _blips                                            // flash up to blips of color
            cycle := 1 - (cycle % 2)                                            // cycles repeating values of 1 and 0
            table.set_bgcolor(tabLe, cycle ? _colb1 : _colb2)                   // cycles tabLe's background color attribute 
            table.cell_set_text_color(tabLe, 0, 0, cycle ? _cols1 : _cols2)     // cycles tabLe cell's string color attribute 
            table.cell_set_text(tabLe, 0, 0, '\n' + _string + nFlsh)            // cycles tabLe cell's string attribute
        else                                                                    // clear tabLe and cell attributes
            table.set_bgcolor(tabLe, color(na))                                 // remove tabLe color 
            table.cell_set_text(tabLe, 0, 0, '')                                // remove tabLe cell text }

// Replace This Code Block With The Conditions Needing To Be Flashed On Chart. {
fastr = ta.ema(hlc3, 1), plot(fastr, '', #ff9800, 2)
slowr = ta.ema(hlc3, 2), plot(slowr, '', #00bcd4, 2)
condU = ta.crossover (fastr, slowr)
condD = ta.crossunder(fastr, slowr)
//}

// Call "the Flasher" function with assigned parameters. Bottom line's call statement supercedes top line's call statement.
flash(agree, 0, condU, blipU, colU1, colU2, mssgU, cntFl, colu1, colu2)
flash(agree, 1, condD, blipD, colD1, colD2, mssgD, cntFl, cold1, cold2)