Spaces:
Running
Running
| // © 2026 Enhanced for Munger Engine Strategy | |
| // This script combines MACD and RSI with multi-timeframe analysis, | |
| // divergence detection, and momentum confirmation to complement | |
| // the Munger Engine weekly value investing strategy. | |
| //@version=6 | |
| indicator("Enhanced RSI & MACD", "RSI/MACD+", false) | |
| // ===================== | |
| // 1. INPUTS | |
| // ===================== | |
| // --- Display Mode --- | |
| display_group = "0. Display Mode" | |
| indicator_mode = input.string("MACD", "Show Indicator", options=["MACD", "RSI"], group = display_group) | |
| // --- MACD Inputs --- | |
| macd_group = "1. MACD Settings" | |
| fast_len = input.int(12, "Fast Length", group = macd_group) | |
| slow_len = input.int(26, "Slow Length", group = macd_group) | |
| signal_len = input.int(9, "Signal Length", group = macd_group) | |
| source = input.source(close, "Source", group = macd_group) | |
| // --- RSI Inputs --- | |
| rsi_group = "2. RSI Settings" | |
| rsi_len = input.int(14, "RSI Length", group = rsi_group) | |
| rsi_ob = input.int(70, "Overbought Level", group = rsi_group) | |
| rsi_os = input.int(30, "Oversold Level", group = rsi_group) | |
| // --- Multi-Timeframe --- | |
| mtf_group = "3. Multi-Timeframe" | |
| show_weekly = input.bool(true, "Show Weekly Indicators", group = mtf_group) | |
| weekly_opacity = input.int(50, "Weekly Line Opacity", minval=0, maxval=100, group = mtf_group) | |
| // --- Divergence Detection --- | |
| div_group = "4. Divergence Detection" | |
| enable_div = input.bool(true, "Enable Divergence Detection", group = div_group) | |
| div_lookback = input.int(5, "Lookback Period", minval=2, maxval=20, group = div_group) | |
| // --- Momentum Confirmation --- | |
| mom_group = "5. Momentum Signals" | |
| show_momentum = input.bool(true, "Show Momentum Background", group = mom_group) | |
| show_info_panel = input.bool(true, "Show Info Panel", group = mom_group) | |
| // ===================== | |
| // 2. CALCULATIONS | |
| // ===================== | |
| // --- Daily MACD & RSI --- | |
| [macdLine, signalLine, histLine] = ta.macd(source, fast_len, slow_len, signal_len) | |
| rsi_val = ta.rsi(source, rsi_len) | |
| // --- Weekly MACD & RSI --- | |
| calc_weekly_indicators() => | |
| [w_macd, w_signal, w_hist] = ta.macd(close, fast_len, slow_len, signal_len) | |
| w_rsi = ta.rsi(close, rsi_len) | |
| [w_macd, w_signal, w_hist, w_rsi] | |
| [w_macdLine, w_signalLine, w_histLine, w_rsi_val] = request.security(syminfo.tickerid, "W", calc_weekly_indicators()) | |
| // --- Momentum State --- | |
| // Bullish: RSI > 50 AND MACD hist rising | |
| // Bearish: RSI < 50 OR MACD hist falling | |
| macd_rising = histLine > histLine[1] | |
| macd_falling = histLine < histLine[1] | |
| momentum_bullish = rsi_val > 50 and macd_rising | |
| momentum_bearish = rsi_val < 50 or macd_falling | |
| momentum_neutral = not momentum_bullish and not momentum_bearish | |
| // Weekly momentum | |
| w_macd_rising = w_histLine > w_histLine[1] | |
| w_momentum_bullish = w_rsi_val > 50 and w_macd_rising | |
| // --- Divergence Detection --- | |
| // Bullish Divergence: Price lower low, RSI higher low | |
| // Bearish Divergence: Price higher high, RSI lower high | |
| find_pivot_low(src, left, right) => | |
| pivot = true | |
| for i = 1 to left | |
| if src[i] < src | |
| pivot := false | |
| for i = 0 to right - 1 | |
| if src[i] < src | |
| pivot := false | |
| pivot | |
| find_pivot_high(src, left, right) => | |
| pivot = true | |
| for i = 1 to left | |
| if src[i] > src | |
| pivot := false | |
| for i = 0 to right - 1 | |
| if src[i] > src | |
| pivot := false | |
| pivot | |
| // Detect divergences and store reason text | |
| var float last_pivot_low_price = na | |
| var float last_pivot_low_rsi = na | |
| var int last_pivot_low_bar = na | |
| var float last_pivot_high_price = na | |
| var float last_pivot_high_rsi = na | |
| var int last_pivot_high_bar = na | |
| bullish_div = false | |
| bearish_div = false | |
| var string bullish_reason = "" | |
| var string bearish_reason = "" | |
| if enable_div | |
| // Check for pivot lows | |
| if find_pivot_low(low, div_lookback, div_lookback) | |
| if not na(last_pivot_low_price) | |
| // Price made lower low, RSI made higher low | |
| if low < last_pivot_low_price and rsi_val > last_pivot_low_rsi | |
| bullish_div := true | |
| bullish_reason := "BULLISH DIVERGENCE\n" + | |
| "------------------------\n" + | |
| "Price: Lower Low\n" + | |
| " Prev: " + str.tostring(last_pivot_low_price, format.mintick) + "\n" + | |
| " Now: " + str.tostring(low, format.mintick) + "\n" + | |
| "RSI: Higher Low\n" + | |
| " Prev: " + str.tostring(last_pivot_low_rsi, "#.2") + "\n" + | |
| " Now: " + str.tostring(rsi_val, "#.2") + "\n" + | |
| "------------------------\n" + | |
| "Signal: Potential reversal up" | |
| last_pivot_low_price := low | |
| last_pivot_low_rsi := rsi_val | |
| last_pivot_low_bar := bar_index | |
| // Check for pivot highs | |
| if find_pivot_high(high, div_lookback, div_lookback) | |
| if not na(last_pivot_high_price) | |
| // Price made higher high, RSI made lower high | |
| if high > last_pivot_high_price and rsi_val < last_pivot_high_rsi | |
| bearish_div := true | |
| bearish_reason := "BEARISH DIVERGENCE\n" + | |
| "------------------------\n" + | |
| "Price: Higher High\n" + | |
| " Prev: " + str.tostring(last_pivot_high_price, format.mintick) + "\n" + | |
| " Now: " + str.tostring(high, format.mintick) + "\n" + | |
| "RSI: Lower High\n" + | |
| " Prev: " + str.tostring(last_pivot_high_rsi, "#.2") + "\n" + | |
| " Now: " + str.tostring(rsi_val, "#.2") + "\n" + | |
| "------------------------\n" + | |
| "Signal: Potential reversal down" | |
| last_pivot_high_price := high | |
| last_pivot_high_rsi := rsi_val | |
| last_pivot_high_bar := bar_index | |
| // ===================== | |
| // 3. PLOTTING | |
| // ===================== | |
| // --- Background for Momentum Zones --- | |
| bgcolor_color = show_momentum ? | |
| (momentum_bullish ? color.new(color.green, 95) : | |
| momentum_bearish ? color.new(color.red, 95) : | |
| color.new(color.gray, 98)) : na | |
| bgcolor(bgcolor_color, title="Momentum Background") | |
| // --- Plot MACD (if selected) --- | |
| show_macd = indicator_mode == "MACD" | |
| histColor = histLine >= 0 ? color.new(color.green, 40) : color.new(color.red, 40) | |
| plot(show_macd ? histLine : na, title="Daily Histogram", style=plot.style_histogram, color=histColor, linewidth=2) | |
| plot(show_macd ? macdLine : na, title="Daily MACD", color=color.new(color.blue, 0), linewidth=2) | |
| plot(show_macd ? signalLine : na, title="Daily Signal", color=color.new(color.orange, 0), linewidth=2) | |
| hline(0, "Zero Line", color.gray, hline.style_dashed) | |
| // --- Plot Weekly MACD (if enabled and MACD mode) --- | |
| w_histColor = w_histLine >= 0 ? color.new(color.green, weekly_opacity) : color.new(color.red, weekly_opacity) | |
| plot(show_macd and show_weekly ? w_histLine : na, title="Weekly Histogram", style=plot.style_line, color=w_histColor, linewidth=1) | |
| plot(show_macd and show_weekly ? w_macdLine : na, title="Weekly MACD", color=color.new(color.blue, weekly_opacity), linewidth=1, style=plot.style_circles) | |
| plot(show_macd and show_weekly ? w_signalLine : na, title="Weekly Signal", color=color.new(color.orange, weekly_opacity), linewidth=1, style=plot.style_circles) | |
| // --- Plot RSI (if selected) --- | |
| show_rsi = indicator_mode == "RSI" | |
| plot(show_rsi ? rsi_val : na, title="Daily RSI", color=color.new(color.purple, 0), linewidth=2) | |
| plot(show_rsi and show_weekly ? w_rsi_val : na, title="Weekly RSI", color=color.new(color.purple, weekly_opacity), linewidth=1, style=plot.style_circles) | |
| // Plot RSI reference levels (only when RSI mode) | |
| ob_line = hline(show_rsi ? rsi_ob : na, "RSI Overbought", color.maroon, hline.style_dashed) | |
| os_line = hline(show_rsi ? rsi_os : na, "RSI Oversold", color.maroon, hline.style_dashed) | |
| mid_line = hline(show_rsi ? 50 : na, "RSI Midline", color.gray, hline.style_dotted) | |
| fill(ob_line, os_line, color=show_rsi ? color.new(color.purple, 90) : na, title="RSI Background Fill") | |
| // --- Divergence Markers with Tooltips --- | |
| // Position labels based on indicator mode for visibility | |
| label_y_bottom = show_rsi ? rsi_os - 5 : histLine < 0 ? histLine * 1.5 : -math.abs(histLine) * 0.5 | |
| label_y_top = show_rsi ? rsi_ob + 5 : histLine > 0 ? histLine * 1.5 : math.abs(histLine) * 0.5 | |
| if bullish_div | |
| label.new(bar_index, label_y_bottom, text="▲", color=color.lime, textcolor=color.white, | |
| style=label.style_label_up, size=size.small, tooltip=bullish_reason) | |
| if bearish_div | |
| label.new(bar_index, label_y_top, text="▼", color=color.red, textcolor=color.white, | |
| style=label.style_label_down, size=size.small, tooltip=bearish_reason) | |
| // ===================== | |
| // 4. INFO PANEL | |
| // ===================== | |
| if show_info_panel and barstate.islast | |
| var table info_panel = table.new(position.bottom_right, 2, 5, border_width=1) | |
| // Header | |
| table.cell(info_panel, 0, 0, "Timeframe", bgcolor=color.gray, text_color=color.white, text_size=size.small) | |
| table.cell(info_panel, 1, 0, "Momentum", bgcolor=color.gray, text_color=color.white, text_size=size.small) | |
| // Daily | |
| daily_state = momentum_bullish ? "BULLISH" : momentum_bearish ? "BEARISH" : "NEUTRAL" | |
| daily_color = momentum_bullish ? color.new(color.green, 70) : momentum_bearish ? color.new(color.red, 70) : color.new(color.gray, 70) | |
| table.cell(info_panel, 0, 1, "Daily", text_size=size.small) | |
| table.cell(info_panel, 1, 1, daily_state, bgcolor=daily_color, text_size=size.small) | |
| // Weekly | |
| weekly_state = w_momentum_bullish ? "BULLISH" : "BEARISH" | |
| weekly_color = w_momentum_bullish ? color.new(color.green, 70) : color.new(color.red, 70) | |
| table.cell(info_panel, 0, 2, "Weekly", text_size=size.small) | |
| table.cell(info_panel, 1, 2, weekly_state, bgcolor=weekly_color, text_size=size.small) | |
| // RSI Comparison | |
| rsi_diff = rsi_val - w_rsi_val | |
| rsi_trend = rsi_diff > 0 ? "D > W" : "D < W" | |
| table.cell(info_panel, 0, 3, "RSI", text_size=size.small) | |
| table.cell(info_panel, 1, 3, rsi_trend, text_size=size.small) | |
| // MACD Trend | |
| macd_trend = macd_rising ? "RISING" : macd_falling ? "FALLING" : "FLAT" | |
| macd_color = macd_rising ? color.new(color.green, 70) : macd_falling ? color.new(color.red, 70) : color.new(color.gray, 70) | |
| table.cell(info_panel, 0, 4, "MACD", text_size=size.small) | |
| table.cell(info_panel, 1, 4, macd_trend, bgcolor=macd_color, text_size=size.small) |