MACD_RSI_trend_following
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © vpirinski
//@version=5



//#region *********** DESCRIPTION ***********
// ================================================== INFO ==================================================
// This indicator can be used to build-up a strategy for trading of assets which are currently in trending phase. 
// My preference is to use it on slowly moving assets like GOLD and on higher timeframes, but practice may show that we find more usefull cases.
// This script uses two indicators - MACD and RSI, as the timeframe that those are extracted for is configurable (defaults with the Chart TF, but can be any other selected by the user).
// The strategy has the following simple idea:
// - Buy if any if the conditions below is true:
//      - The selected TF MACD line crosses above the signal line and the TF RSI is above the user selected trigger value
//      - The selected TF MACD line is above the signal line and the TF RSI crosses above the user selected trigger value
// - Once we're in position we wait for the selected TF MACD line to cross below the signal line, and then we set a SL at the low of thet bar

// ================================================== DETAILS and USAGE ==================================================
// In the current implementation I find two possible use cases for the indicator:
// - as a stand-alone indicator on the chart which can also fire alerts that can help to determine if we want to manually enter/exit trades based on them
// - can be used to connect to the Signal input of the TTS (TempalteTradingStrategy) by jason5480 in order to backtest it, thus effectively turning it into a strategy (instructions below in TTS CONNECTIVITY section)
// Trading period can be selected from the indicator itself to limit to more interesting periods.
// Arrow indications are drawn on the chart to indicate the trading conditions met in the script - green arrow for a buy signal indication and orange for LTF crossunder to indicate setting of SL.

// ================================================== SETTINGS ==================================================
// Leaving all of the settings as in vanilla use case, as both the MACD and RSI indicator's settings follow the default ones for the stand-alone indicators themselves.
// The start-end date is a time filter that can be extermely usefull when backtesting different time periods.
// Pesonal preference is using the script on a D/W timeframe, while the indicator is configured to use Monthly chart.
// The default value of the RSI filter is left to 50, which can be changed. I.e. if the RSI is above 50 we have a regime filter based on the MACD criteria.

// ================================================== EXTERNAL LIBS ==================================================
// The script uses a couple of external libraries:
// - HeWhoMustNotBeNamed/enhanced_ta/14 - collection of TA indicators
// - jason5480/tts_convention/3 - more details about the Template Trading Strategy below
// I would like to highly appreciate and credit the work of both HeWhoMustNotBeNamed and jason5480 for providing them to the community.

// ================================================== TTS SETTINGS (NEEDED IF USED TO BACKTEST WITH TTS) ==================================================
// The TempalteTradingStrategy is a strategy script developed in Pine by jason5480, which I recommend for quick turn-around of testing different ideas on a proven and tested framework
// I cannot give enough credit to the developer for the efforts put in building of the infrastructure, so I advice everyone that wants to use it first to get familiar with the concept and by checking 
// by checking jason5480's profile https://www.tradingview.com/u/jason5480/#published-scripts
// The TTS itself is extremely functional and have a lot of properties, so its functionality is beyond the scope of the current script - 
// Again, I strongly recommend to be thoroughly epxlored by everyone that plans on using it.
// In the nutshell it is a script that can be feed with buy/sell signals from an external indicator script and based on many configuration options it can determine how to execute the trades.
// The TTS has many settings that can be applied, so below I will cover only the ones that differ from the default ones, at least according to my testing - do your own research, you may find something even better :)
// The current/latest version that I've been using as of writing and testing this script is TTSv48
// Settings which differ from the default ones:
//   - from                   - False                                               (time filter is from the indicator script itself)
//   - Deal Conditions Mode   - External                                            (take enter/exit conditions from an external script)
//   - 🔌Signal 🛈➡          - MACD_RSI_trend_following: 🔌Signal to TTSv48        (this is the output from the indicator script, according to the TTS convention)
//   - Sat/Sun                - true                                                (for crypto, in order to trade 24/7)
//   - Order Type​​             - STOP                                                (perform stop order)
//   - Distance Method​​        - HHLL                                                (HigherHighLowerLow - in order to set the SL according to the strategy definition from above)
//
// The next are just personal preferenes, you can feel free to experiment according to your trading style
//   - Take Profit Targets    - 0                                                   (either 100% in or out, no incremental stepping in or out of positions)
//   - Dist Mul|Len Long/Short- 10                                                  (make sure that we don't close on profitable trades by any reason)
//   - Quantity Method        - EQUITY                                              (personal backtesting preference is to consider each backtest as a separate portfolio, so determine the position size by 100% of the allocated equity size)
//   - Equity %               - 100                                                 (note above)



//#region *********** STRATEGY_SETUP *********** 
indicator(title                 =   'MACD_RSI_trend_following', 
          shorttitle            =   'MACD_RSI_trend_following', 
          overlay               =   true,  
          explicit_plot_zorder  =   true
         ) 

//#endregion ========================================================================================================



//#region *********** LIBRARIES *********** 
import HeWhoMustNotBeNamed/enhanced_ta/14 as eta
import jason5480/tts_convention/3         as tts_conv
//#endregion ========================================================================================================



//#region *********** USER_INPUT *********** 
var string COMMON_GROUP_STR = "Common"
i_timeframe                 = input.timeframe(title = "Timeframe",         defval = "",     group = COMMON_GROUP_STR)
i_repaint_en                = true //input.bool     (title = "Repainting On/Off", defval = true,   group = COMMON_GROUP_STR, tooltip="Off for use as an Indicator to avoid repainting. On for use in Strategies so that trades can respond to realtime data.")

var string MACD_GROUP_STR   = "MACD"
i_macd_ma_source            = input.source   (title = "Source",             defval = close, group = MACD_GROUP_STR)
i_macd_osc_ma_type          = input.string   (title = "Osc MA type",        defval = "ema", group = MACD_GROUP_STR, options = ["ema", "sma", "rma", "hma", "wma", "vwma", "swma"])
i_macd_signal_line_ma_type  = input.string   (title = "Signal MA type",     defval = "ema", group = MACD_GROUP_STR, options = ["ema", "sma", "rma", "hma", "wma", "vwma", "swma"])
i_macd_fast_ma_length       = input.int      (title = "Fast MA Length",     defval = 12,    group = MACD_GROUP_STR)
i_macd_slow_ma_length       = input.int      (title = "Slow MA Length",     defval = 26,    group = MACD_GROUP_STR)
i_macd_signal_length        = input.int      (title = "Low MACD Hist",      defval = 9,     group = MACD_GROUP_STR)

var string RSI_GROUP_STR    = "RSI"
i_rsi_source                = input.source   (title = "Source",             defval = close, group = RSI_GROUP_STR)
i_rsi_length                = input.int      (title = "Length",             defval = 14,    group = RSI_GROUP_STR)
i_rsi_trigger_value         = input.int      (title = "RSI trigger value",  defval = 50,    group = RSI_GROUP_STR)

var string TIME_GROUP_STR   = "Start and End Time"
i_start_time                = input.time     (title="Start Date",          defval=timestamp("01 Jan 2000 13:30 +0000"), group=TIME_GROUP_STR)
i_end_time                  = input.time     (title="End Date",            defval=timestamp("1 Jan 2099 19:30 +0000"),  group=TIME_GROUP_STR)
//#endregion ========================================================================================================



//#region *********** COMMON_FUNCTIONS *********** 
// Function offering a repainting/no-repainting version of the HTF data (but does not work on tuples).
// It has the advantage of using only one `security()` call for both.
// The built-in MACD function behaves identically to Repainting On in the custom function below. In other words _repaint = TRUE. 
// https://www.tradingview.com/script/cyPWY96u-How-to-avoid-repainting-when-using-security-PineCoders-FAQ/
f_security(_symbol, _tf, _src, _repaint) => request.security(_symbol, _tf, _src[_repaint ? 0 : barstate.isrealtime ? 1 : 0])[_repaint ? 0 : barstate.isrealtime ? 0 : 1]
//#endregion ========================================================================================================



//#region *********** LOGIC *********** 
// Get the current TF MACD and RSI and then interpolate them for the user TF
fast_ma                 = eta.ma(source = i_macd_ma_source, maType = i_macd_osc_ma_type, length = i_macd_fast_ma_length)
slow_ma                 = eta.ma(source = i_macd_ma_source, maType = i_macd_osc_ma_type, length = i_macd_slow_ma_length)
ctf_macd_line           = fast_ma - slow_ma
ctf_signal_line         = eta.ma(source = ctf_macd_line, maType = i_macd_signal_line_ma_type, length = i_macd_signal_length)
ctf_hist_line           = ctf_macd_line - ctf_signal_line
ctf_rsi                 = ta.rsi(i_rsi_source, i_rsi_length)

macd_line               = f_security(syminfo.tickerid, i_timeframe, ctf_macd_line,   i_repaint_en)
signal_line             = f_security(syminfo.tickerid, i_timeframe, ctf_signal_line, i_repaint_en)
hist_line               = f_security(syminfo.tickerid, i_timeframe, ctf_hist_line,   i_repaint_en)
rsi                     = f_security(syminfo.tickerid, i_timeframe, ctf_rsi,         i_repaint_en)

// Determine the strategy trading conditions
macd_crossover          = ta.crossover (macd_line, signal_line)
macd_crossunder         = ta.crossunder(macd_line, signal_line)
rsi_crossover           = ta.crossover (rsi, i_rsi_trigger_value)

// Filters
time_and_bar_filter     = barstate.isconfirmed and ((time >= i_start_time) and (time <= i_end_time))
macd_crossover_filter   = macd_crossover and (rsi > i_rsi_trigger_value)
rsi_crossover_filter    = (macd_line > signal_line) and rsi_crossover
strategy_buy_fiter      = macd_crossover_filter or rsi_crossover_filter
strategy_set_sl_filter  = macd_crossunder

// Strategy buy/set SL
buy_signal              = time_and_bar_filter and strategy_buy_fiter
set_sl_signal           = time_and_bar_filter and strategy_set_sl_filter
//#endregion ========================================================================================================



//#region *********** BUY_&_SELL_SIGNALS TO TTS *********** 
tts_deal_conditions = tts_conv.DealConditions.new(
     startLongDeal      = buy_signal,
     startShortDeal     = false,
	 endLongDeal        = set_sl_signal,
	 endShortDeal       = false,
	 cnlStartLongDeal   = false,
	 cnlStartShortDeal  = false,
	 cnlEndLongDeal     = false,
	 cnlEndShortDeal    = false)

plot(series = tts_conv.getSignal(tts_deal_conditions), title = '🔌Signal to TTS', color = color.olive, display = display.data_window + display.status_line)
//#endregion ========================================================================================================



//#region *********** DEBUG_&_PLOTS *********** 
plotshape(buy_signal,     style=shape.triangleup,   location=location.bottom,   size = size.tiny, color=buy_signal     ? color.rgb(19, 231, 26)  : na)
plotshape(set_sl_signal,  style=shape.triangledown, location=location.top,      size = size.tiny, color=set_sl_signal  ? color.rgb(216, 129, 71) : na)
//#endregion ========================================================================================================



//#region *********** ALERTS *********** 
alertcondition(buy_signal,     "BuySignal",   "MACD and RSI conditions satisfied for {{ticker}} - buy at price {{close}}")
alertcondition(set_sl_signal,  "SetSLSignal", "MACD crossunder - set SL for {{ticker}} at price {{close}}")
//#endregion ========================================================================================================