The 20MA game
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Wilson-IV

//@version=5
indicator("The 20MA game", max_labels_count = 500, max_bars_back = 5000, overlay = true)

//===============================================================================
// === Discription ===
//===============================================================================

//   Strategy name                          : The 20MA game
//   Developer                              : Wilson-IV

//   Change log:
//   -----------------------------------------------------------------------------

//   Version 2.5
//   - Entry Level added

//   Version 2.4
//    - Suggested Entrypoints improved 

//   Version 2.3
//    - Suggested Entrypoints added 

//   Version 2.2
//    - Nitfty Box added: just a simple Nitfty box to make analyzing your chart more comfortable

//   Version 2.1
//    - 200 EMA Channel added: this is the area between the 200 EMA High price and the 200 EMA low price
//    - Black background removed

//   Version 2.0
//    - Upperband and Lowerband 20MA of the 20 MA line
//    - LONG/ SHORT area added
//    - Option to plot 20MA, 200MA and/or 20MA of the 20MA line
//    - LONG/SHORT Labels removed

//   Version 1.0
//    - Initial release

//===============================================================================



//===============================================================================
//=== Tooltips, Group- and Inline names ===
//===============================================================================

// === Inline ===
string inline_Date                                           = "Date"

// === Group names ===
string group_Starting_date                                   = "Starting date"
string group_Plottings                                       = "Plottings"
string group_Suggested_Entrypoints                           = "Suggested Entrypoints"
string group_Variables                                       = "Variables"

//===============================================================================



//===============================================================================
//=== Backtest date settings ===
//===============================================================================

startDate                                                    = input.int(title = "Start Date"   , defval = 1    , minval = 1     , maxval = 31    , group = group_Starting_date , inline = inline_Date)
startMonth                                                   = input.int(title = "Start Month"  , defval = 1    , minval = 1     , maxval = 12    , group = group_Starting_date , inline = inline_Date)
startYear                                                    = input.int(title = "Start Year"   , defval = 2023 , minval = 1800  , maxval = 2100  , group = group_Starting_date , inline = inline_Date) 
startHour                                                    = input.int(title = "Start Hour"   , defval = 0    , minval = 0     , maxval = 23    , group = group_Starting_date , inline = inline_Date)
startMinute                                                  = input.int(title = "Start Minute" , defval = 0    , minval = 0     , maxval = 59    , group = group_Starting_date , inline = inline_Date)
startGMT                                                     = input.int(title = "GMT + "       , defval = 2    , minval = 0     , maxval = 12    , group = group_Starting_date , inline = inline_Date)

//=== Start date for Backtesting [Change the GMT setting for your country. E.g.: Amsterdam is GMT+2] ===
Start_backtest                                               = time >= timestamp(("GMT+" + str.tostring(startGMT)), startYear, startMonth, startDate, startHour, startMinute)  ? true : false

//===============================================================================



//===============================================================================
//=== Variables ===
//===============================================================================

//=== Source === 
float Source                                                 = input.source(close, "Source", group = group_Variables)

//=== MA === 
float _20MA                                                  = ta.ema(Source, 20)
float _200MA                                                 = ta.ema(Source, 200)
float _20MA_of_20MA                                          = ta.ema(_20MA, 20)
bool bln_20MA_IS_UP                                          = _20MA > _20MA[1]
bool bln_20MA_IS_DOWN                                        = _20MA <= _20MA[1]
bool bln_20MA_of_20MA_IS_UP                                  = _20MA_of_20MA > _20MA_of_20MA[1]
bool bln_20MA_of_20MA_IS_DOWN                                = _20MA_of_20MA <= _20MA_of_20MA[1]
int int_20MA_of_20MA_START_GOING_UP                          = ta.barssince(bln_20MA_of_20MA_IS_DOWN)
int int_20MA_of_20MA_START_GOING_DOWN                        = ta.barssince(bln_20MA_of_20MA_IS_UP)

//=== 200MA Channel ===
float _200MA_HIGH                                            = ta.ema(high, 200)
float _200MA_LOW                                             = ta.ema(low, 200)

//=== Upperband / Lowerband 20MA of the 20MA ===
float dbl_Average_distance_from_High_to_20MA_of_20MA_part_1  = high >= _20MA_of_20MA ? high -_20MA_of_20MA : 0
float dbl_Average_distance_from_Low_to_20MA_of_20MA_part_1   = low <= _20MA_of_20MA ? _20MA_of_20MA - low : 0

float dbl_Average_distance_from_High_to_20MA_of_20MA_part_2  = ta.sma(dbl_Average_distance_from_High_to_20MA_of_20MA_part_1, 20)
float dbl_Average_distance_from_Low_to_20MA_of_20MA_part_2   = ta.sma(dbl_Average_distance_from_Low_to_20MA_of_20MA_part_1, 20)

float dbl_Upperband_High                                     = _20MA_of_20MA + ta.sma(dbl_Average_distance_from_High_to_20MA_of_20MA_part_2, 3)
float dbl_Upperband_Low                                      = _20MA_of_20MA - ta.sma(dbl_Average_distance_from_Low_to_20MA_of_20MA_part_2, 3)

bool bln_Area_LONG                                           = ((dbl_Upperband_High[2] <= dbl_Upperband_High[1]) and (dbl_Upperband_High[1] <= dbl_Upperband_High)) ? true : bln_20MA_of_20MA_IS_UP ? true : false
bool bln_Area_SHORT                                          = ((dbl_Upperband_Low[2] >= dbl_Upperband_Low[1]) and (dbl_Upperband_Low[1] >= dbl_Upperband_Low)) ? true : bln_20MA_of_20MA_IS_DOWN ? true : false

//=== Candlestick ===
Candle_WhiteBody                                             = open < close 
Candle_BlackBody                                             = open > close
Candle_NoBody                                                = open == close

//=== Entry Level ===
var float dbl_Entry_Level                                    = 0.
dbl_Entry_Level                                              := bln_20MA_of_20MA_IS_UP and bln_20MA_of_20MA_IS_DOWN[1] ? close : bln_20MA_of_20MA_IS_UP[1] and bln_20MA_of_20MA_IS_DOWN ? close : nz(dbl_Entry_Level[1],0)

//===============================================================================



//===============================================================================
//=== Suggested Entrypoints ===
//===============================================================================

//Bars 20MA of 20MA start going UP/DOWN
int int_Bars_20MA_of_20MA_START_GOING_UP                     = input.int(title = "Bars 20MA_of_20MA start going UP" , defval = 7 , minval = 1 , maxval = 500 , step = 1, group = group_Suggested_Entrypoints)
int int_Bars_20MA_of_20MA_START_GOING_DOWN                   = input.int(title = "Bars 20MA_of_20MA start going DOWN" , defval = 7 , minval = 1 , maxval = 500 , step = 1, group = group_Suggested_Entrypoints)

//Distance between each Suggested Entrypoints
float dbl_Delta_LONG                                         = input.float(title = "Distance between each Suggested Entrypoints LONG (%)" , defval = 0.5 , minval = 0.5 , maxval = 25 , step = 0.25, group = group_Suggested_Entrypoints) * 0.01
float dbl_Delta_SHORT                                        = input.float(title = "Distance between each Suggested Entrypoints SHORT (%)" , defval = 0.5 , minval = 0.5 , maxval = 25 , step = 0.25, group = group_Suggested_Entrypoints) * 0.01

var float dbl_Start_Price                                    = 0.       //Sarting price when the cart changes from Green to Red or visaversa

var float dbl_MAX_price_20MA_of_20MA_IS_UP                   = 0.       //MAX price when the 20MA is in the green(upwards)
var float dbl_MAX_price_20MA_of_20MA_IS_DOWN                 = 9999999. //MAX price when the 20MA is in the red(downwards)

bool bln_Suggested_Entrypoint_LONG                           = false    //When to Enter LONG
var float dbl_Suggested_Entrypoint_price_LONG                = 0.       //Price when to Enter LONG
var float dbl_Suggested_Entrypoint_previous_price_LONG       = 0.       //Previous Price when to Enter LONG

bool bln_Suggested_Entrypoint_SHORT                          = false    //When to Enter SHORT
var float dbl_Suggested_Entrypoint_price_SHORT               = 0.       //Price when to Enter SHORT
var float dbl_Suggested_Entrypoint_previous_price_SHORT      = 0.       //Previous Price when to Enter SHORT

var bool bln_Pierced_LONG                                    = false    //The moment the price pierced through the previous Entrypoint price LONG
var bool bln_Pierced_SHORT                                   = false    //The moment the price pierced through the previous Entrypoint price SHORT

var bool bln_Show_Suggested_Entrypoint_price                 = false    //Show Suggested Entrypoint price

if Start_backtest

    //Entrypoint LONG
    if bln_20MA_of_20MA_IS_UP and bln_20MA_of_20MA_IS_DOWN[1] 

        dbl_MAX_price_20MA_of_20MA_IS_UP              := 0
        dbl_MAX_price_20MA_of_20MA_IS_DOWN            := 9999999.

        dbl_Suggested_Entrypoint_price_LONG           := 0
        dbl_Suggested_Entrypoint_previous_price_LONG  := 0

        dbl_Suggested_Entrypoint_price_SHORT          := 0
        dbl_Suggested_Entrypoint_previous_price_SHORT := 0

        bln_Pierced_LONG                              := false
        bln_Pierced_SHORT                             := false

        dbl_Start_Price                               := na

    if bln_20MA_of_20MA_IS_UP

        dbl_MAX_price_20MA_of_20MA_IS_DOWN := na
        dbl_MAX_price_20MA_of_20MA_IS_UP := math.max(dbl_MAX_price_20MA_of_20MA_IS_UP, close)

        //=== Criteria LONG ===
        bool Criteria_01 = dbl_MAX_price_20MA_of_20MA_IS_UP[1] > dbl_MAX_price_20MA_of_20MA_IS_UP[2]
        bool Criteria_02 = dbl_MAX_price_20MA_of_20MA_IS_DOWN[2] > 0 and dbl_MAX_price_20MA_of_20MA_IS_UP[1] > 0
        bool Criteria_03 = close <= (1 + dbl_Delta_LONG) * _20MA_of_20MA
        bool Criteria_04 = int_20MA_of_20MA_START_GOING_UP <= int_Bars_20MA_of_20MA_START_GOING_UP

        if ((Criteria_01 or Criteria_02) and Candle_BlackBody) or (Criteria_03 and Criteria_04)
            
            if dbl_Suggested_Entrypoint_price_LONG  == 0 
                
                dbl_Suggested_Entrypoint_previous_price_LONG := 0
                dbl_Suggested_Entrypoint_price_LONG          := close
                
                bln_Suggested_Entrypoint_LONG                := true
                
                bln_Pierced_LONG                             := false

            else if close >= (1 + dbl_Delta_LONG) * dbl_Suggested_Entrypoint_price_LONG 
                
                dbl_Suggested_Entrypoint_previous_price_LONG := dbl_Suggested_Entrypoint_price_LONG
                dbl_Suggested_Entrypoint_price_LONG          := close

                if bln_Pierced_LONG == true
                    
                    bln_Show_Suggested_Entrypoint_price := true

                    bln_Suggested_Entrypoint_LONG       := true
                    bln_Pierced_LONG                    := false
                
                else
                
                    bln_Show_Suggested_Entrypoint_price := false

        if low <= dbl_Suggested_Entrypoint_previous_price_LONG
            
            bln_Pierced_LONG := true


    //Entrypoint SHORT
    if bln_20MA_of_20MA_IS_UP[1] and bln_20MA_of_20MA_IS_DOWN 

        dbl_MAX_price_20MA_of_20MA_IS_UP              := 0
        dbl_MAX_price_20MA_of_20MA_IS_DOWN            := 9999999.

        dbl_Suggested_Entrypoint_price_LONG           := 0
        dbl_Suggested_Entrypoint_previous_price_LONG  := 9999999.

        dbl_Suggested_Entrypoint_price_SHORT          := 0
        dbl_Suggested_Entrypoint_previous_price_SHORT := 9999999.

        bln_Pierced_LONG                              := false
        bln_Pierced_SHORT                             := false

        dbl_Start_Price                               := na

    if bln_20MA_of_20MA_IS_DOWN

        dbl_MAX_price_20MA_of_20MA_IS_UP := na
        dbl_MAX_price_20MA_of_20MA_IS_DOWN := math.min(dbl_MAX_price_20MA_of_20MA_IS_DOWN, close)

        //=== Criteria SHORT ===
        bool Criteria_01 = dbl_MAX_price_20MA_of_20MA_IS_DOWN[1] < dbl_MAX_price_20MA_of_20MA_IS_DOWN[2]
        bool Criteria_02 = dbl_MAX_price_20MA_of_20MA_IS_DOWN[1] > 0 and dbl_MAX_price_20MA_of_20MA_IS_UP[2] > 0
        bool Criteria_03 = close >= (1 - dbl_Delta_SHORT) * _20MA_of_20MA
        bool Criteria_04 = int_20MA_of_20MA_START_GOING_DOWN <= int_Bars_20MA_of_20MA_START_GOING_DOWN

        if ((Criteria_01 or Criteria_02) and Candle_WhiteBody) or (Criteria_03 and Criteria_04)
            
            if dbl_Suggested_Entrypoint_price_SHORT  == 0 
                
                dbl_Suggested_Entrypoint_previous_price_SHORT := 9999999.
                dbl_Suggested_Entrypoint_price_SHORT          := close
                
                bln_Suggested_Entrypoint_SHORT                := true

                bln_Pierced_SHORT                             := false

                bln_Show_Suggested_Entrypoint_price           := true

            else if close <= (1 - dbl_Delta_SHORT) * dbl_Suggested_Entrypoint_price_SHORT 
                
                dbl_Suggested_Entrypoint_previous_price_SHORT := dbl_Suggested_Entrypoint_price_SHORT
                dbl_Suggested_Entrypoint_price_SHORT          := close

                if bln_Pierced_SHORT == true
                    
                    bln_Show_Suggested_Entrypoint_price := true

                    bln_Suggested_Entrypoint_SHORT      := true
                    bln_Pierced_SHORT                   := false
                
                else
                
                    bln_Show_Suggested_Entrypoint_price := false

        if high >= dbl_Suggested_Entrypoint_previous_price_SHORT
            
            bln_Pierced_SHORT := true

//===============================================================================


//===============================================================================
//=== Plottings ===
//===============================================================================

//=== Use plottings ? ===
bool blnUse_20MA                                             = input.bool(title = "Use 20MA plot ?"             , defval = false , group = group_Plottings)
bool blnUse_200MA                                            = input.bool(title = "Use 200MA plot ?"            , defval = false , group = group_Plottings)
bool blnUse_200MA_bands                                      = input.bool(title = "Use 200MA bands ?"           , defval = false , group = group_Plottings)
bool blnUse_20MA_of_20MA_bands                               = input.bool(title = "Use 20MA of 20MA_bands ?"    , defval = false , group = group_Plottings)
bool blnShow_Suggested_Entrypoint                            = input.bool(title = "Show Suggested Entrypoint ?" , defval = false , group = group_Plottings)
bool blnShow_Entry_Level                                     = input.bool(title = "Show Entry Levels ?"         , defval = true  , group = group_Plottings)

//=== 20MA + 200MA ===
plot(0. , title = "------------------------------" , color = color.new(color.white, 100))
plot(0. , title = "--- 20MA + 200MA --------" , color = color.new(color.white, 100))

P20MA       = plot(Start_backtest and blnUse_20MA ? _20MA : na, title = "20MA", color = color.new(color.yellow , 0) , linewidth = 1)
P200MA      = plot(Start_backtest and blnUse_200MA ? _200MA : na, title = "200MA", color = color.new(color.blue , 0) , linewidth = 3)
P20MA20MA   = plot(Start_backtest ? _20MA_of_20MA : na, title = "20MA of the 20MA", color = _20MA_of_20MA[1] < _20MA_of_20MA ? color.new(#00FF00 , 0) : color.new(#FF0000 , 0) , linewidth = 3)

UPPERBAND_HIGH   = plot(Start_backtest and blnUse_20MA_of_20MA_bands ? dbl_Upperband_High : na, title = "Upperband High" , color = bln_Area_LONG ? color.new(color.green, 70) : color.new(color.red, 70), style = plot.style_circles, linewidth = 1)
UPPERBAND_LOW    = plot(Start_backtest and blnUse_20MA_of_20MA_bands ? dbl_Upperband_Low : na, title = "Upperband Low" , color = bln_Area_SHORT ? color.new(color.red, 70) : color.new(color.green, 70), style = plot.style_circles, linewidth = 1)

fill(P20MA20MA, UPPERBAND_HIGH, title = "LONG area", color = blnUse_20MA_of_20MA_bands ? (bln_Area_LONG ? color.new(color.green, 70) : color.new(color.red, 70)) : na)
fill(UPPERBAND_LOW, P20MA20MA, title = "SHORT area", color = blnUse_20MA_of_20MA_bands ? (bln_Area_SHORT ? color.new(color.red, 70) : color.new(color.green, 70)): na)

//=== 200MA Channel ===
_200EMA_HIGH     = plot(Start_backtest and blnUse_200MA_bands ? _200MA_HIGH : na, title = "_200MA_HIGH" , color = color.new(#ffffff, 30) , style = plot.style_line , linewidth = 1)
_200EMA_LOW      = plot(Start_backtest and blnUse_200MA_bands ? _200MA_LOW : na, title = "_200MA_LOW" , color = color.new(#ffffff , 30) , style = plot.style_line , linewidth = 1)

fill(_200EMA_HIGH, _200EMA_LOW, title = "200 EMA Channel", color = color.new(#ffffff , 95))

//=== Suggested Entrypoints ===
plot(Start_backtest and blnShow_Suggested_Entrypoint and bln_Suggested_Entrypoint_LONG ? dbl_Suggested_Entrypoint_price_LONG : na, 'Suggested Entrypoint LONG', color=color.new(color.green, 0), style = plot.style_circles, linewidth = 7)
plot(Start_backtest and blnShow_Suggested_Entrypoint and bln_Show_Suggested_Entrypoint_price ? dbl_Suggested_Entrypoint_price_LONG : na, 'Entrpoint price LONG', color=color.new(color.white, 0), style=plot.style_circles, linewidth = 1)
plotshape(Start_backtest and blnShow_Suggested_Entrypoint and bln_Suggested_Entrypoint_LONG, size = size.small, style= shape.triangledown, color=color.new(color.green, 0), location = location.abovebar)

plot(Start_backtest and blnShow_Suggested_Entrypoint and bln_Suggested_Entrypoint_SHORT ? dbl_Suggested_Entrypoint_price_SHORT : na, 'Suggested Entrypoint SHORT', color=color.new(#ff4343, 0), style = plot.style_circles, linewidth = 7)
plot(Start_backtest and blnShow_Suggested_Entrypoint and bln_Show_Suggested_Entrypoint_price ? dbl_Suggested_Entrypoint_price_SHORT : na, 'Entrpoint price SHORT', color=color.new(color.white, 0), style=plot.style_circles, linewidth = 1)
plotshape(Start_backtest and blnShow_Suggested_Entrypoint and bln_Suggested_Entrypoint_SHORT, size = size.small, style= shape.triangleup, color=color.new(#ff4343, 0), location = location.belowbar)

//=== Entry Level ===
plot(Start_backtest and blnShow_Entry_Level ? dbl_Entry_Level : na, color = _20MA_of_20MA[1] < _20MA_of_20MA ? color.new(#00FF00 , 30) : color.new(#FF0000 , 30) , style = plot.style_circles , linewidth = 1)

//===============================================================================
