// ============================================================================ // © algonexta // This script is for education and research; it does not guarantee results. // Verify this source in TradingView before use. // ============================================================================ //@version=6 indicator("MacIce Hidden EMA Indicator", "MacIce", overlay = true, max_labels_count = 500) // MacIce for TradingView // 1) EMA60 / EMA240 cross sets the active direction. // 2) In downturn, every confirmed hidden bearish divergence gets a sell arrow. // 3) In upturn, every confirmed hidden bullish divergence gets a buy arrow. // 4) Indicator only. No strategy orders, no trading functions. // // Signal timing: a pivot is only known after `pivotRight` more bars have closed. // The big arrow is drawn on the confirmation bar, which is the bar where the // alert fires, so the chart history matches what a live user would have seen. // A small dot marks the pivot bar itself, so the turning point stays visible. string GROUP_EMA = "EMA Cross" string GROUP_HIDDEN = "Hidden Divergence" string GROUP_DISPLAY = "Display" float source = input.source(close, "Source", group = GROUP_EMA) int fastEmaPeriod = input.int(60, "Fast EMA", minval = 2, group = GROUP_EMA) int slowEmaPeriod = input.int(240, "Slow EMA", minval = 5, group = GROUP_EMA) bool requireEmaSide = input.bool(false, "Require price on EMA side", group = GROUP_EMA) int pivotLeft = input.int(1, "Pivot left bars", minval = 1, group = GROUP_HIDDEN) int pivotRight = input.int(1, "Pivot right bars", minval = 1, group = GROUP_HIDDEN) int macdFast = input.int(12, "MACD fast", minval = 1, group = GROUP_HIDDEN) int macdSlow = input.int(26, "MACD slow", minval = 2, group = GROUP_HIDDEN) int macdSignal = input.int(9, "MACD signal", minval = 1, group = GROUP_HIDDEN) bool resetPivotsOnCross = input.bool(false, "Reset pivot memory on each cross", group = GROUP_HIDDEN) bool moreSignals = input.bool(true, "More signals / trend pivots", group = GROUP_HIDDEN) bool showEmaLines = input.bool(false, "Show EMA lines", group = GROUP_DISPLAY) bool showCrossLabels = input.bool(true, "Show cross labels", group = GROUP_DISPLAY) bool showPivotMarkers = input.bool(true, "Show pivot dot (where the turn happened)", group = GROUP_DISPLAY) int signalsToKeep = input.int(20, "Previous signals to show", minval = 20, maxval = 90, group = GROUP_DISPLAY) int crossLabelsToKeep = input.int(20, "Previous cross labels to show", minval = 1, maxval = 90, group = GROUP_DISPLAY) float emaFast = ta.ema(source, fastEmaPeriod) float emaSlow = ta.ema(source, slowEmaPeriod) float atrValue = ta.atr(14) bool bullCross = ta.crossover(emaFast, emaSlow) bool bearCross = ta.crossunder(emaFast, emaSlow) var int trendDirection = 0 var int trendStartBar = na if bullCross trendDirection := 1 trendStartBar := bar_index else if bearCross trendDirection := -1 trendStartBar := bar_index if trendDirection == 0 trendDirection := emaFast > emaSlow ? 1 : emaFast < emaSlow ? -1 : 0 [macdLine, signalLine, histLine] = ta.macd(source, macdFast, macdSlow, macdSignal) float pivotHigh = ta.pivothigh(high, pivotLeft, pivotRight) float pivotLow = ta.pivotlow(low, pivotLeft, pivotRight) bool hasPivotHigh = not na(pivotHigh) bool hasPivotLow = not na(pivotLow) int pivotBar = bar_index - pivotRight var float previousHighPrice = na var float previousHighMacd = na var int previousHighBar = na var float previousLowPrice = na var float previousLowMacd = na var int previousLowBar = na if resetPivotsOnCross and (bullCross or bearCross) previousHighPrice := na previousHighMacd := na previousHighBar := na previousLowPrice := na previousLowMacd := na previousLowBar := na bool pivotAfterTrendStart = na(trendStartBar) ? true : pivotBar > trendStartBar bool sellEmaOk = not requireEmaSide or (close[pivotRight] < emaFast[pivotRight] and close[pivotRight] < emaSlow[pivotRight]) bool buyEmaOk = not requireEmaSide or (close[pivotRight] > emaFast[pivotRight] and close[pivotRight] > emaSlow[pivotRight]) bool hiddenBear = false bool hiddenBull = false if hasPivotHigh float highMacd = macdLine[pivotRight] bool strictBear = not na(previousHighPrice) and pivotHigh < previousHighPrice and highMacd > previousHighMacd bool softBear = moreSignals and not na(previousHighPrice) and (pivotHigh < previousHighPrice or highMacd > previousHighMacd) and histLine[pivotRight] <= histLine[pivotRight + 1] bool trendPivotBear = moreSignals and not na(previousHighPrice) hiddenBear := trendDirection == -1 and pivotAfterTrendStart and sellEmaOk and (strictBear or softBear or trendPivotBear) previousHighPrice := pivotHigh previousHighMacd := highMacd previousHighBar := pivotBar if hasPivotLow float lowMacd = macdLine[pivotRight] bool strictBull = not na(previousLowPrice) and pivotLow > previousLowPrice and lowMacd < previousLowMacd bool softBull = moreSignals and not na(previousLowPrice) and (pivotLow > previousLowPrice or lowMacd < previousLowMacd) and histLine[pivotRight] >= histLine[pivotRight + 1] bool trendPivotBull = moreSignals and not na(previousLowPrice) hiddenBull := trendDirection == 1 and pivotAfterTrendStart and buyEmaOk and (strictBull or softBull or trendPivotBull) previousLowPrice := pivotLow previousLowMacd := lowMacd previousLowBar := pivotBar plot(showEmaLines ? emaFast : na, "EMA 60", color = color.red, linewidth = 2) plot(showEmaLines ? emaSlow : na, "EMA 240", color = color.blue, linewidth = 2) var label[] signalLabels = array.new_label() var label[] pivotLabels = array.new_label() var label[] crossLabels = array.new_label() // Big arrow on the confirmation bar (the current bar), where the alert fires. addSignalLabel(bool isBuy) => float arrowPrice = isBuy ? low - atrValue * 0.25 : high + atrValue * 0.25 label arrowLabel = label.new( bar_index, arrowPrice, isBuy ? "▲" : "▼", xloc = xloc.bar_index, yloc = yloc.price, style = label.style_none, color = color.new(color.white, 100), textcolor = isBuy ? color.lime : color.red, size = size.huge, tooltip = "Signal confirmed here (" + str.tostring(pivotRight) + " bar(s) after the pivot)") array.push(signalLabels, arrowLabel) while array.size(signalLabels) > signalsToKeep label.delete(array.shift(signalLabels)) // Small dot on the pivot bar itself, so the turning point stays visible. addPivotMarker(bool isBuy) => float dotPrice = isBuy ? low[pivotRight] - atrValue[pivotRight] * 0.25 : high[pivotRight] + atrValue[pivotRight] * 0.25 label dotLabel = label.new( pivotBar, dotPrice, "●", xloc = xloc.bar_index, yloc = yloc.price, style = label.style_none, color = color.new(color.white, 100), textcolor = isBuy ? color.new(color.lime, 35) : color.new(color.red, 35), size = size.tiny, tooltip = "Pivot bar (known only " + str.tostring(pivotRight) + " bar(s) later)") array.push(pivotLabels, dotLabel) while array.size(pivotLabels) > signalsToKeep label.delete(array.shift(pivotLabels)) if hiddenBear addSignalLabel(false) if showPivotMarkers addPivotMarker(false) if hiddenBull addSignalLabel(true) if showPivotMarkers addPivotMarker(true) addCrossLabel(bool isBullCross) => float crossPrice = (emaFast + emaSlow) * 0.5 float labelPrice = isBullCross ? crossPrice - atrValue * 0.35 : crossPrice + atrValue * 0.35 label crossLabel = label.new( bar_index, labelPrice, "Cross", xloc = xloc.bar_index, yloc = yloc.price, style = label.style_none, color = color.new(color.blue, 100), textcolor = color.rgb(41, 98, 255), size = size.normal) array.push(crossLabels, crossLabel) while array.size(crossLabels) > crossLabelsToKeep label.delete(array.shift(crossLabels)) if showCrossLabels and bullCross addCrossLabel(true) if showCrossLabels and bearCross addCrossLabel(false) alertcondition(hiddenBear, "MacIce Sell Hidden", "MacIce sell hidden divergence on {{ticker}} {{interval}}") alertcondition(hiddenBull, "MacIce Buy Hidden", "MacIce buy hidden divergence on {{ticker}} {{interval}}")