Market Cycle Projection Engine

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

    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.
ProRealAI ProRealAI New

Stuck on this ProBuilder code?

Describe what this topic is trying to build, in plain English, and ProRealAI writes the ProRealTime™ indicator, screener or system for you.

Available in 7 languages
Try ProRealAI

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
ProRealCode ProRealCode
Loading...