Market Cycle Projection Engine

Viewing 1 post (of 1 total)
  • Author
    Posts
  • #259682 quote
    Iván González
    Moderator
    Master

    Here is a translation of an indicator requested by @ciccarelli-franco

    //-------------------------------------------------//
    // PRC_Market Cycle Projection Engine
    // Adapted from PineScript [AleksDU]
    // version = 0
    // 30.03.2026
    // Iván González @ www.prorealcode.com
    // Sharing ProRealTime knowledge
    //-------------------------------------------------//
    defparam drawonlastbaronly = true
    
    // === INPUTS ===
    cycleLen = 50       // Cycle lookback (bars)
    showZones = 1       // Show cycle zones (1=yes)
    showLevels = 1      // Show key S/R levels (1=yes)
    srLookback = 30     // S/R pivot lookback
    levelExt = 30       // Extend levels (bars)
    showProj = 1        // Show projection (1=yes)
    projLen = 100       // Projection bars
    projMode = 1        // 0=Cycle Average, 1=Last Cycle, 2=ATR Multiple
    showDash = 1        // Show Dashboard (1=yes)
    
    // ================================================================
    // MODULE A: CYCLE DETECTION
    // ================================================================
    
    // --- ATR ---
    atr14 = averagetruerange[14](close)
    atrSlow = averagetruerange[cycleLen](close)
    
    // --- Cycle Range ---
    cycleHigh = highest[cycleLen](high)
    cycleLow = lowest[cycleLen](low)
    cycleRange = cycleHigh - cycleLow
    cycleMid = (cycleHigh + cycleLow) / 2
    
    // --- Linear Regression Slope (manual, per bar) ---
    // i=0 oldest, i=N-1 current → positive slope = uptrend
    sumIY = 0
    sumCloseN = 0
    FOR i = 0 TO cycleLen - 1 DO
       sumIY = sumIY + i * close[cycleLen - 1 - i]
       sumCloseN = sumCloseN + close[cycleLen - 1 - i]
    NEXT
    sumI = cycleLen * (cycleLen - 1) / 2
    sumII = cycleLen * (cycleLen - 1) * (2 * cycleLen - 1) / 6
    lrDenom = cycleLen * sumII - sumI * sumI
    IF lrDenom <> 0 THEN
       lrSlope = (cycleLen * sumIY - sumI * sumCloseN) / lrDenom
    ELSE
       lrSlope = 0
    ENDIF
    
    // --- Normalized slope ---
    lrSlopeNorm = lrSlope / max(atr14, 0.0001)
    
    // --- Volatility state ---
    atrRatio = atr14 / max(atrSlow, 0.0001)
    isExpanding = (atrRatio > 1.1)
    isContracting = (atrRatio < 0.85)
    
    // --- Volume state ---
    volSMA = average[20](volume)
    volRising = (volume > volSMA * 1.2)
    volFalling = (volume < volSMA * 0.8)
    
    // --- Price position (0=bottom, 1=top) ---
    pricePos = (close - cycleLow) / max(cycleRange, 0.0001)
    
    // ================================================================
    // PHASE CLASSIFICATION
    // 1=Accumulation, 2=Markup, 3=Distribution, 4=Markdown, 5=Transition
    // ================================================================
    phase = 5
    IF lrSlopeNorm > 0.1 AND isExpanding THEN
       phase = 2
    ELSIF lrSlopeNorm < -0.1 AND isExpanding THEN
       phase = 4
    ELSIF lrSlopeNorm >= -0.1 AND lrSlopeNorm <= 0.1 AND pricePos < 0.4 THEN
       phase = 1
    ELSIF lrSlopeNorm >= -0.1 AND lrSlopeNorm <= 0.1 AND pricePos >= 0.4 THEN
       phase = 3
    ENDIF
    
    // Phase colors
    IF phase = 1 THEN
       rPh = 0
       gPh = 188
       bPh = 212
    ELSIF phase = 2 THEN
       rPh = 0
       gPh = 230
       bPh = 118
    ELSIF phase = 3 THEN
       rPh = 255
       gPh = 152
       bPh = 0
    ELSIF phase = 4 THEN
       rPh = 255
       gPh = 82
       bPh = 82
    ELSE
       rPh = 124
       gPh = 77
       bPh = 255
    ENDIF
    
    // ================================================================
    // PHASE CHANGE DETECTION + ZONE STORAGE
    // ================================================================
    once prevPhase = 0
    once phaseStartBar = 0
    once phaseHi = high
    once phaseLo = low
    once zoneCnt = 0
    
    phaseChanged = (phase <> prevPhase AND prevPhase <> 0)
    
    IF phaseChanged THEN
       // Store ending phase as a zone (FIFO of 6)
       IF zoneCnt < 6 THEN
          FOR k = zoneCnt DOWNTO 1 DO
             $zStart[k] = $zStart[k - 1]
             $zEnd[k] = $zEnd[k - 1]
             $zHi[k] = $zHi[k - 1]
             $zLo[k] = $zLo[k - 1]
             $zPh[k] = $zPh[k - 1]
          NEXT
          zoneCnt = zoneCnt + 1
       ELSE
          FOR k = 5 DOWNTO 1 DO
             $zStart[k] = $zStart[k - 1]
             $zEnd[k] = $zEnd[k - 1]
             $zHi[k] = $zHi[k - 1]
             $zLo[k] = $zLo[k - 1]
             $zPh[k] = $zPh[k - 1]
          NEXT
       ENDIF
       
       zmid = (phaseHi + phaseLo) / 2
       $zStart[0] = phaseStartBar
       $zEnd[0] = barindex
       $zHi[0] = zmid + atr14 * 1.5
       $zLo[0] = zmid - atr14 * 1.5
       $zPh[0] = prevPhase
       
       // Reset for new phase
       prevPhase = phase
       phaseStartBar = barindex
       phaseHi = high
       phaseLo = low
    ELSE
       IF prevPhase = 0 THEN
          prevPhase = phase
          phaseStartBar = barindex
       ENDIF
       IF high > phaseHi THEN
          phaseHi = high
       ENDIF
       IF low < phaseLo THEN
          phaseLo = low
       ENDIF
    ENDIF
    
    phaseDuration = barindex - phaseStartBar
    
    // ================================================================
    // BAR COLORING (every bar)
    // ================================================================
    drawcandle(open, high, low, close) coloured(rPh, gPh, bPh)
    
    // ================================================================
    // MODULE B: S/R LEVELS (pivot tracking, every bar)
    // ================================================================
    once phCnt = 0
    once plCnt = 0
    
    isPH = 0
    IF barindex >= 2 * srLookback + 1 THEN
       IF high[srLookback] = highest[2 * srLookback + 1](high) THEN
          isPH = 1
       ENDIF
    ENDIF
    isPL = 0
    IF barindex >= 2 * srLookback + 1 THEN
       IF low[srLookback] = lowest[2 * srLookback + 1](low) THEN
          isPL = 1
       ENDIF
    ENDIF
    
    // Store last 5 pivots (FIFO)
    IF isPH THEN
       IF phCnt < 5 THEN
          FOR k = phCnt DOWNTO 1 DO
             $phVal[k] = $phVal[k - 1]
             $phBar[k] = $phBar[k - 1]
          NEXT
          phCnt = phCnt + 1
       ELSE
          FOR k = 4 DOWNTO 1 DO
             $phVal[k] = $phVal[k - 1]
             $phBar[k] = $phBar[k - 1]
          NEXT
       ENDIF
       $phVal[0] = high[srLookback]
       $phBar[0] = barindex - srLookback
    ENDIF
    
    IF isPL THEN
       IF plCnt < 5 THEN
          FOR k = plCnt DOWNTO 1 DO
             $plVal[k] = $plVal[k - 1]
             $plBar[k] = $plBar[k - 1]
          NEXT
          plCnt = plCnt + 1
       ELSE
          FOR k = 4 DOWNTO 1 DO
             $plVal[k] = $plVal[k - 1]
             $plBar[k] = $plBar[k - 1]
          NEXT
       ENDIF
       $plVal[0] = low[srLookback]
       $plBar[0] = barindex - srLookback
    ENDIF
    
    // ================================================================
    // MODULE C: PROJECTION
    // ================================================================
    projUp = (phase = 1 OR phase = 4)
    
    projAmpl = 0
    IF projMode = 0 THEN
       projAmpl = atrSlow * sqrt(cycleLen) * 0.4
    ELSIF projMode = 1 THEN
       projAmpl = cycleRange * 0.75
    ELSE
       projAmpl = atr14 * 30
    ENDIF
    
    // ================================================================
    // DRAWING (last bar only)
    // ================================================================
    IF islastbarupdate THEN
       
       // --- Cycle Zones ---
       IF showZones AND zoneCnt > 0 THEN
          FOR z = 0 TO zoneCnt - 1 DO
             zPh = $zPh[z]
             IF zPh = 1 THEN
                rZ = 0
                gZ = 188
                bZ = 212
             ELSIF zPh = 2 THEN
                rZ = 0
                gZ = 230
                bZ = 118
             ELSIF zPh = 3 THEN
                rZ = 255
                gZ = 152
                bZ = 0
             ELSIF zPh = 4 THEN
                rZ = 255
                gZ = 82
                bZ = 82
             ELSE
                rZ = 124
                gZ = 77
                bZ = 255
             ENDIF
             drawrectangle($zStart[z], $zHi[z], $zEnd[z], $zLo[z]) coloured(rZ, gZ, bZ, 200) fillcolor(rZ, gZ, bZ, 30)
          NEXT
       ENDIF
       
       // --- S/R Levels ---
       IF showLevels THEN
          // Pivot resistances
          IF phCnt > 0 THEN
             FOR i = 0 TO phCnt - 1 DO
                drawsegment($phBar[i], $phVal[i], barindex + levelExt, $phVal[i]) coloured(255, 82, 82, 160) style(dottedline, 1)
             NEXT
          ENDIF
          // Pivot supports
          IF plCnt > 0 THEN
             FOR i = 0 TO plCnt - 1 DO
                drawsegment($plBar[i], $plVal[i], barindex + levelExt, $plVal[i]) coloured(0, 230, 118, 160) style(dottedline, 1)
             NEXT
          ENDIF
          // Cycle High / Low / Mid
          drawsegment(barindex - cycleLen, cycleHigh, barindex + levelExt, cycleHigh) coloured(255, 82, 82) style(line, 2)
          drawtext("Cycle High", barindex + levelExt + 3, cycleHigh+0.25*atr14) coloured(255, 82, 82)
          drawsegment(barindex - cycleLen, cycleLow, barindex + levelExt, cycleLow) coloured(0, 230, 118) style(line, 2)
          drawtext("Cycle Low", barindex + levelExt + 3, cycleLow-0.25*atr14) coloured(0, 230, 118)
          drawsegment(barindex - cycleLen, cycleMid, barindex + levelExt, cycleMid) coloured(124, 77, 255, 160) style(dottedline, 1)
          drawtext("Mid", barindex + levelExt + 3, cycleMid) coloured(124, 77, 255)
       ENDIF
       
       // --- Projection ---
       IF showProj THEN
          IF projUp THEN
             ep = close + projAmpl
             rA = 0
             gA = 230
             bA = 118
          ELSE
             ep = close - projAmpl
             rA = 255
             gA = 82
             bA = 82
          ENDIF
          // Main line
          drawsegment(barindex, close, barindex + projLen, ep) coloured(rA, gA, bA) style(line, 3)
          // Upper/lower bounds
          drawsegment(barindex, close + atr14 * 3, barindex + projLen, ep + atr14 * 3) coloured(rA, gA, bA, 160) style(dottedline, 1)
          drawsegment(barindex, close - atr14 * 3, barindex + projLen, ep - atr14 * 3) coloured(rA, gA, bA, 160) style(dottedline, 1)
          // Label with %
          projPct = round(projAmpl / close * 1000) / 10
          IF projUp THEN
             drawtext("+#projPct#%", barindex + projLen + 6, ep) coloured(rA, gA, bA)
          ELSE
             drawtext("-#projPct#%", barindex + projLen + 6, ep) coloured(rA, gA, bA)
          ENDIF
       ENDIF
       
       // --- Dashboard ---
       IF showDash THEN
          // Phase name
          IF phase = 1 THEN
             drawtext("Phase: Accumulation", -200, -20) anchor(topright, xshift, yshift) coloured(0, 188, 212)
          ELSIF phase = 2 THEN
             drawtext("Phase: Markup", -200, -20) anchor(topright, xshift, yshift) coloured(0, 230, 118)
          ELSIF phase = 3 THEN
             drawtext("Phase: Distribution", -200, -20) anchor(topright, xshift, yshift) coloured(255, 152, 0)
          ELSIF phase = 4 THEN
             drawtext("Phase: Markdown", -200, -20) anchor(topright, xshift, yshift) coloured(255, 82, 82)
          ELSE
             drawtext("Phase: Transition", -200, -20) anchor(topright, xshift, yshift) coloured(124, 77, 255)
          ENDIF
          // Duration
          drawtext("Duration: #phaseDuration# bars", -200, -40) anchor(topright, xshift, yshift) coloured(200, 200, 200)
          // Strength
          cycleStr = round(abs(pricePos - 0.5) * 200)
          drawtext("Strength: #cycleStr#/100", -200, -60) anchor(topright, xshift, yshift) coloured(200, 200, 200)
          // Position %
          posPct = round(pricePos * 100)
          drawtext("Position: #posPct#%", -200, -80) anchor(topright, xshift, yshift) coloured(200, 200, 200)
          // Volatility
          IF isExpanding THEN
             drawtext("Volatility: Expanding", -200, -100) anchor(topright, xshift, yshift) coloured(255, 152, 0)
          ELSIF isContracting THEN
             drawtext("Volatility: Contracting", -200, -100) anchor(topright, xshift, yshift) coloured(0, 188, 212)
          ELSE
             drawtext("Volatility: Normal", -200, -100) anchor(topright, xshift, yshift) coloured(150, 150, 150)
          ENDIF
          // Projection
          IF projUp THEN
             drawtext("Projection: Upward #projPct#%", -200, -120) anchor(topright, xshift, yshift) coloured(0, 230, 118)
          ELSE
             drawtext("Projection: Downward #projPct#%", -200, -120) anchor(topright, xshift, yshift) coloured(255, 82, 82)
          ENDIF
       ENDIF
       
    ENDIF
    
    RETURN
    

    The indicator’s logic includes a part that colors the bars. To do this, I’ve created a new indicator.

    //-------------------------------------------------//
    // PRC_Market Cycle Bar Color
    // Companion to PRC_Market Cycle Projection Engine
    // version = 0
    // 30.03.2026
    // Iván González @ www.prorealcode.com
    // Sharing ProRealTime knowledge
    //-------------------------------------------------//
    // === INPUTS ===
    cycleLen = 50       // Cycle lookback (bars)
    
    // === CYCLE DETECTION ===
    atr14 = averagetruerange[14]
    atrSlow = averagetruerange[cycleLen]
    
    cycleHigh = highest[cycleLen](high)
    cycleLow = lowest[cycleLen](low)
    cycleRange = cycleHigh - cycleLow
    
    // Linear Regression Slope
    sumIY = 0
    sumCloseN = 0
    FOR i = 0 TO cycleLen - 1 DO
       sumIY = sumIY + i * close[cycleLen - 1 - i]
       sumCloseN = sumCloseN + close[cycleLen - 1 - i]
    NEXT
    sumI = cycleLen * (cycleLen - 1) / 2
    sumII = cycleLen * (cycleLen - 1) * (2 * cycleLen - 1) / 6
    lrDenom = cycleLen * sumII - sumI * sumI
    IF lrDenom <> 0 THEN
       lrSlope = (cycleLen * sumIY - sumI * sumCloseN) / lrDenom
    ELSE
       lrSlope = 0
    ENDIF
    
    lrSlopeNorm = lrSlope / max(atr14, 0.0001)
    atrRatio = atr14 / max(atrSlow, 0.0001)
    isExpanding = (atrRatio > 1.1)
    pricePos = (close - cycleLow) / max(cycleRange, 0.0001)
    
    // Phase classification
    IF lrSlopeNorm > 0.1 AND isExpanding THEN
       drawcandle(open, high, low, close) coloured(0, 230, 118)
    ELSIF lrSlopeNorm < -0.1 AND isExpanding THEN
       drawcandle(open, high, low, close) coloured(255, 82, 82)
    ELSIF lrSlopeNorm >= -0.1 AND lrSlopeNorm <= 0.1 AND pricePos < 0.4 THEN
       drawcandle(open, high, low, close) coloured(0, 188, 212)
    ELSIF lrSlopeNorm >= -0.1 AND lrSlopeNorm <= 0.1 AND pricePos >= 0.4 THEN
       drawcandle(open, high, low, close) coloured(255, 152, 0)
    ELSE
       drawcandle(open, high, low, close) coloured(124, 77, 255)
    ENDIF
    
    RETURN
    


    Nicolas and robertogozzi thanked this post
    IBE-Diario.png IBE-Diario.png
Viewing 1 post (of 1 total)
  • You must be logged in to reply to this topic.

TradingView to ProRealTime Translation Center

New Reply
Author
Summary

This topic contains 1 voice and has 0 replies.

Topic Details
Forum: TradingView to ProRealTime Translation Center Forum
Started: 03/31/2026
Status: Active
Attachments: 1 files
Logo Logo
Loading...