The Gann Pivot Indicator: A Deep Dive into the Trading Philosophy and Mechanics

Discussion in 'Technical Analysis' started by MarkBrown, Aug 2, 2025 at 8:05 PM.

  1. MarkBrown

    MarkBrown

    The Fundamental Trading Concept

    This indicator is built on one of the most profound observations in technical analysis: markets don't move in straight lines, but rather in a series of swings or waves. W.D. Gann recognized that these swings create a rhythm in the market, and by understanding this rhythm, traders can anticipate future price movements.

    The Core Philosophy

    The indicator is looking for what I call "exhaustion patterns" - specific market structures that suggest a trend is running out of steam and may be ready to reverse. Think of it like watching ocean waves: before a big wave crashes and reverses, there are subtle signs in the water's movement that experienced surfers can read. This indicator is trying to read those same subtle signs in price action.

    Understanding Market Structure Through Pivots

    What is a Pivot?

    A pivot is a turning point in the market - a place where price stopped going in one direction and started going in another. Imagine you're hiking up a mountain:

    • A Pivot High is like reaching a peak where you have to start going down
    • A Pivot Low is like reaching a valley where you have to start going up
    The indicator identifies these using a simple 3-bar pattern:

    • Pivot High: Yesterday's high is higher than both today's high AND the day before yesterday's high
    • Pivot Low: Yesterday's low is lower than both today's low AND the day before yesterday's low
    The Genius of the Trading Logic

    For Buy Signals - The Detailed Process

    Let me walk you through exactly what happens when the indicator looks for a buy signal:

    1. New Pivot High Forms: The market makes a pivot high (a local peak)
    2. Historical Context Check: The indicator asks, "Is this pivot high lower than the absolute highest high the market has ever made?" This filters out pivots at all-time highs, where buying might be dangerous.
    3. Looking for the Previous Higher High: The indicator then looks backward in time for a previous pivot high that was HIGHER than the current one. This is crucial - it's looking for evidence that the market is making LOWER HIGHS, a classic sign of a downtrend.
    4. Time Filter: It only considers previous highs that are at least 'GannDays' (default 4) bars ago. This ensures we're looking at meaningful swings, not just minor fluctuations.
    5. Finding the Lowest Point: Between that previous higher high and now, the indicator finds the LOWEST pivot low. This represents the maximum pessimism or selling pressure in that period.
    6. Final Validation: If the time from that lowest low to the current pivot high is at least 'GannDays', it's saying: "The market fell from a higher high, made a significant low, and has now rallied back up for at least 4 days to make this current high. This could be the start of a new uptrend."
    Why This Works - The Psychology

    What's happening here is profound. The pattern identifies:

    • Failed Continuation: The market couldn't make a higher high (bearish)
    • Significant Selling: A meaningful low was established (maximum fear)
    • Recovery Rally: Price has now rallied for several days off that low
    • Potential Reversal: This could be early buyers stepping in, sensing value
    For Sell Signals - The Mirror Image

    The sell signal logic is the exact opposite:

    1. New Pivot Low Forms: But it's not the absolute lowest low ever
    2. Finds Previous Lower Low: Looks for evidence of HIGHER LOWS (uptrend characteristic)
    3. Identifies Highest High: Finds the peak of optimism between the previous low and now
    4. Time Validation: Ensures enough time has passed for this to be meaningful
    The psychology here is identifying when an uptrend might be exhausting - higher lows (bullish) but now failing to continue, with a significant high (maximum optimism) followed by several days of decline.

    The Brilliant Use of Time

    Gann was obsessed with time, and this indicator honors that. The 'GannDays' parameter (default 4) serves multiple purposes:

    1. Filters Noise: Ensures we're looking at meaningful swings, not random fluctuations
    2. Respects Market Rhythm: Many markets have natural 3-5 day rhythms
    3. Allows Patterns to Develop: Gives the market time to "prove" its intention
    Signal Management and Discipline

    Signal Expiration (SigExpir = 50)
    This is brilliant risk management. A signal doesn't last forever - if the market doesn't trigger your entry within 50 bars, the signal expires. This prevents you from acting on stale information.

    Entry Mechanism
    • Buy Signal: Places a stop order 1 tick ABOVE the pivot high
    • Sell Signal: Places a stop order 1 tick BELOW the pivot low
    This ensures you only enter if the market actually breaks through these levels, confirming the reversal.

    The Array Storage System

    The indicator stores up to 1500 historical pivots. Why?

    1. Pattern Recognition: Needs historical context to identify patterns
    2. Adaptive Analysis: Can look far back for significant levels
    3. Market Memory: Respects that old pivots can still be relevant
    Real-World Trading Application

    Imagine you're trading the S&P 500:

    1. Market has been falling for weeks
    2. A pivot low forms at 4,200 (the fear point)
    3. Market rallies for 5 days to 4,250
    4. Pivot high forms at 4,250
    5. Indicator looks back, sees previous high was 4,300
    6. Calculates: "We fell from 4,300 to 4,200, now rallied to 4,250"
    7. Signal generated: Buy stop at 4,251
    If the market continues up and breaks 4,251, you're in. If it fails and falls back, you're protected.

    Why This Approach is Powerful
    1. Objective Rules: No subjective interpretation needed
    2. Risk Definition: You know exactly where to enter and can place stops
    3. Patience: Waits for high-probability setups
    4. Time-Tested: Based on Gann's century-old principles
    5. Adaptable: Works across different markets and timeframes
    The Hidden Wisdom

    The deepest insight here is that the indicator is NOT trying to catch exact tops and bottoms. Instead, it's waiting for the market to show its hand - to prove that a reversal might be underway - before suggesting action. This is the difference between prediction and reaction, and it's why this approach has survived for decades.

    The indicator essentially says: "Don't try to catch a falling knife. Wait for the knife to hit the ground, bounce, and show it might be safe to pick up."

    python code

    Code:
    import numpy as np
    import pandas as pd
    from typing import Tuple, List, Optional
    import matplotlib.pyplot as plt
    from dataclasses import dataclass
    from datetime import datetime
    
    @dataclass
    class PivotPoint:
        """Class to store pivot point information"""
        bar: int
        price: float
        pivot_type: str  # 'high' or 'low'
    
    class GannPivotIndicator:
        """
        GANN PIVOT INDICATOR
        Python implementation of the Gann Pivot Trading System
    
        This indicator identifies pivot highs and lows, then looks for specific
        patterns based on Gann's principles to generate buy and sell signals.
        """
    
        def __init__(self, gann_days: int = 4, sig_expir: int = 50, max_array_size: int = 1500):
            """
            Initialize the Gann Pivot Indicator
     
            Parameters:
            -----------
            gann_days : int
                Minimum number of days required between pivots for a valid signal
            sig_expir : int
                Signal expiration - how many bars a signal remains valid
            max_array_size : int
                Maximum number of pivots to store in memory
            """
            self.gann_days = gann_days
            self.sig_expir = sig_expir
            self.max_array_size = max_array_size
     
            # Initialize variables
            self.market_high = -np.inf
            self.market_low = np.inf
     
            # Pivot storage
            self.pivot_highs: List[PivotPoint] = []
            self.pivot_lows: List[PivotPoint] = []
     
            # Signal tracking
            self.temp_buy_price = 0
            self.temp_buy_bar = 0
            self.temp_buy_on = False
     
            self.temp_sell_price = 0
            self.temp_sell_bar = 0
            self.temp_sell_on = False
     
            # Track current bar
            self.current_bar = 0
     
            # Store signals for plotting
            self.buy_signals = []
            self.sell_signals = []
     
        def _add_pivot_high(self, bar: int, price: float):
            """Add a pivot high to the list with bounds checking"""
            pivot = PivotPoint(bar=bar, price=price, pivot_type='high')
     
            if len(self.pivot_highs) >= self.max_array_size:
                # Remove oldest pivot to make room
                self.pivot_highs.pop(0)
     
            self.pivot_highs.append(pivot)
     
        def _add_pivot_low(self, bar: int, price: float):
            """Add a pivot low to the list with bounds checking"""
            pivot = PivotPoint(bar=bar, price=price, pivot_type='low')
     
            if len(self.pivot_lows) >= self.max_array_size:
                # Remove oldest pivot to make room
                self.pivot_lows.pop(0)
         
            self.pivot_lows.append(pivot)
     
        def _identify_pivots(self, high: pd.Series, low: pd.Series, idx: int):
            """
            Identify pivot highs and lows using 3-bar patterns
     
            Pivot High: High[1] > High[0] and High[1] > High[2]
            Pivot Low: Low[1] < Low[0] and Low[1] < Low[2]
            """
            if idx >= 2:  # Need at least 3 bars
                # Check for Pivot High
                if high.iloc[idx] < high.iloc[idx-1] and high.iloc[idx-1] > high.iloc[idx-2]:
                    self._add_pivot_high(self.current_bar - 1, high.iloc[idx-1])
             
                # Check for Pivot Low
                if low.iloc[idx] > low.iloc[idx-1] and low.iloc[idx-1] < low.iloc[idx-2]:
                    self._add_pivot_low(self.current_bar - 1, low.iloc[idx-1])
             
        def _check_buy_setup(self):
            """
            Check for buy setup conditions
     
            Logic:
            1. Find a new pivot high that's lower than market's all-time high
            2. Look back for a previous higher pivot high (at least gann_days ago)
            3. Find the lowest pivot low between them
            4. If conditions met, set buy signal
            """
            if len(self.pivot_highs) < 2 or len(self.pivot_lows) < 1:
                return
         
            latest_pivot_high = self.pivot_highs[-1]
     
            # Check if this is a new pivot high and not at market high
            if (latest_pivot_high.bar == self.current_bar - 1 and
                latest_pivot_high.price < self.market_high):
         
                # Find previous higher pivot high
                prev_higher_bar = None
                for i in range(len(self.pivot_highs) - 2, -1, -1):
                    if self.pivot_highs.price > latest_pivot_high.price:
                        prev_higher_bar = self.pivot_highs.bar
                        break
                     
                if prev_higher_bar is None:
                    return
                 
                # Check if enough bars between pivots
                bar_count = latest_pivot_high.bar - prev_higher_bar
                if bar_count < self.gann_days:
                    return
                 
                # Find lowest pivot low between the two pivot highs
                lowest_low = None
                lowest_low_bar = None
             
                for pivot_low in self.pivot_lows:
                    if pivot_low.bar > prev_higher_bar and pivot_low.bar < latest_pivot_high.bar:
                        if lowest_low is None or pivot_low.price < lowest_low:
                            lowest_low = pivot_low.price
                            lowest_low_bar = pivot_low.bar
                         
                if lowest_low_bar is None:
                    return
                 
                # Check if enough days from low to current pivot high
                low_to_high_days = latest_pivot_high.bar - lowest_low_bar
             
                if (low_to_high_days >= self.gann_days and
                    latest_pivot_high.bar > self.temp_buy_bar):
                 
                    self.temp_buy_price = latest_pivot_high.price
                    self.temp_buy_bar = latest_pivot_high.bar
                    self.temp_buy_on = True
                 
        def _check_sell_setup(self):
            """
            Check for sell setup conditions
         
            Logic:
            1. Find a new pivot low that's higher than market's all-time low
            2. Look back for a previous lower pivot low (at least gann_days ago)
            3. Find the highest pivot high between them
            4. If conditions met, set sell signal
            """
            if len(self.pivot_lows) < 2 or len(self.pivot_highs) < 1:
                return
             
            latest_pivot_low = self.pivot_lows[-1]
         
            # Check if this is a new pivot low and not at market low
            if (latest_pivot_low.bar == self.current_bar - 1 and
                latest_pivot_low.price > self.market_low):
             
                # Find previous lower pivot low
                prev_lower_bar = None
                bar_count = 0
             
                for i in range(len(self.pivot_lows) - 2, -1, -1):
                    if self.pivot_lows.price < latest_pivot_low.price:
                        prev_lower_bar = self.pivot_lows.bar
                        bar_count = latest_pivot_low.bar - prev_lower_bar
                        break
                     
                if prev_lower_bar is None or bar_count < self.gann_days:
                    return
                 
                # Find highest pivot high between the two pivot lows
                highest_high = None
                highest_high_bar = None
             
                for pivot_high in self.pivot_highs:
                    if pivot_high.bar > prev_lower_bar and pivot_high.bar < latest_pivot_low.bar:
                        if highest_high is None or pivot_high.price > highest_high:
                            highest_high = pivot_high.price
                            highest_high_bar = pivot_high.bar
                         
                if highest_high_bar is None:
                    return
                 
                # Check if enough days from high to current pivot low
                high_to_low_days = latest_pivot_low.bar - highest_high_bar
             
                if (high_to_low_days >= self.gann_days and
                    latest_pivot_low.bar > self.temp_sell_bar):
                 
                    self.temp_sell_price = latest_pivot_low.price
                    self.temp_sell_bar = latest_pivot_low.bar
                    self.temp_sell_on = True
                 
        def process_bar(self, high: float, low: float, high_series: pd.Series,
                       low_series: pd.Series, idx: int) -> Tuple[Optional[float], Optional[float]]:
            """
            Process a single bar of data
         
            Returns:
            --------
            Tuple of (buy_signal_price, sell_signal_price) or (None, None) if no signals
            """
            self.current_bar = idx + 1  # CurrentBar in EasyLanguage is 1-based
         
            # Update market highs and lows
            if high > self.market_high:
                self.market_high = high
            if low < self.market_low:
                self.market_low = low
             
            # Identify pivots
            self._identify_pivots(high_series, low_series, idx)
         
            # Check for new setups
            self._check_buy_setup()
            self._check_sell_setup()
         
            buy_signal = None
            sell_signal = None
         
            # Check if buy signal is active and valid
            if self.temp_buy_on:
                if (high < self.temp_buy_price and
                    self.current_bar - self.temp_buy_bar <= self.sig_expir):
                    buy_signal = self.temp_buy_price + 0.01  # Adding 1 tick
                else:
                    self.temp_buy_on = False
                 
            # Check if sell signal is active and valid
            if self.temp_sell_on:
                if (low > self.temp_sell_price and
                    self.current_bar - self.temp_sell_bar <= self.sig_expir):
                    sell_signal = self.temp_sell_price - 0.01  # Subtracting 1 tick
                else:
                    self.temp_sell_on = False
                 
            return buy_signal, sell_signal
     
        def analyze(self, data: pd.DataFrame) -> pd.DataFrame:
            """
            Analyze a DataFrame with OHLC data
         
            Parameters:
            -----------
            data : pd.DataFrame
                DataFrame with columns: 'high', 'low' (and optionally 'open', 'close')
             
            Returns:
            --------
            pd.DataFrame with additional columns: 'buy_signal', 'sell_signal'
            """
            # Reset state
            self.__init__(self.gann_days, self.sig_expir, self.max_array_size)
         
            # Prepare result dataframe
            result = data.copy()
            result['buy_signal'] = np.nan
            result['sell_signal'] = np.nan
         
            # Process each bar
            for i in range(len(data)):
                buy_signal, sell_signal = self.process_bar(
                    data['high'].iloc,
                    data['low'].iloc,
                    data['high'],
                    data['low'],
                    i
                )
             
                if buy_signal is not None:
                    result.loc[result.index, 'buy_signal'] = buy_signal
                    self.buy_signals.append((result.index, buy_signal))
                 
                if sell_signal is not None:
                    result.loc[result.index, 'sell_signal'] = sell_signal
                    self.sell_signals.append((result.index, sell_signal))
                 
            return result
     
        def plot_signals(self, data: pd.DataFrame, result: pd.DataFrame,
                        figsize: Tuple[int, int] = (15, 8)):
            """
            Plot the price data with buy and sell signals
            """
            fig, ax = plt.subplots(figsize=figsize)
         
            # Plot candlestick chart (simplified)
            for idx in range(len(data)):
                high = data['high'].iloc[idx]
                low = data['low'].iloc[idx]
             
                # Plot high-low bars
                ax.plot([idx, idx], [low, high], 'k-', linewidth=0.5)
             
                # Add open/close if available
                if 'open' in data.columns and 'close' in data.columns:
                    open_price = data['open'].iloc[idx]
                    close_price = data['close'].iloc[idx]
                    color = 'g' if close_price > open_price else 'r'
                    ax.plot([idx-0.3, idx+0.3], [open_price, open_price], color, linewidth=1)
                    ax.plot([idx-0.3, idx+0.3], [close_price, close_price], color, linewidth=1)
         
            # Plot buy signals
            buy_x = []
            buy_y = []
            for idx, signal in enumerate(result['buy_signal']):
                if not pd.isna(signal):
                    buy_x.append(idx)
                    buy_y.append(signal)
                 
            ax.scatter(buy_x, buy_y, color='green', marker='^', s=100,
                      label='Buy Signal', zorder=5)
         
            # Plot sell signals
            sell_x = []
            sell_y = []
            for idx, signal in enumerate(result['sell_signal']):
                if not pd.isna(signal):
                    sell_x.append(idx)
                    sell_y.append(signal)
                 
            ax.scatter(sell_x, sell_y, color='red', marker='v', s=100,
                      label='Sell Signal', zorder=5)
         
            # Mark pivot points
            for pivot in self.pivot_highs[-20:]:  # Show last 20 pivot highs
                if pivot.bar < len(data):
                    ax.plot(pivot.bar-1, pivot.price, 'b.', markersize=8)
                 
            for pivot in self.pivot_lows[-20:]:  # Show last 20 pivot lows
                if pivot.bar < len(data):
                    ax.plot(pivot.bar-1, pivot.price, 'r.', markersize=8)
         
            ax.set_xlabel('Bar Number')
            ax.set_ylabel('Price')
            ax.set_title(f'Gann Pivot Indicator (GannDays={self.gann_days}, SigExpir={self.sig_expir})')
            ax.legend()
            ax.grid(True, alpha=0.3)
         
            plt.tight_layout()
            plt.show()
         
        def get_pivot_statistics(self) -> dict:
            """
            Get statistics about the pivots and signals generated
            """
            return {
                'total_pivot_highs': len(self.pivot_highs),
                'total_pivot_lows': len(self.pivot_lows),
                'total_buy_signals': len(self.buy_signals),
                'total_sell_signals': len(self.sell_signals),
                'market_high': self.market_high,
                'market_low': self.market_low
            }
    
    
    # Example usage
    if __name__ == "__main__":
        # Create sample data
        np.random.seed(42)
        dates = pd.date_range('2023-01-01', periods=500, freq='D')
     
        # Generate synthetic price data
        trend = np.cumsum(np.random.randn(500) * 0.5)
        noise = np.random.randn(500) * 2
        base_price = 100 + trend + noise
     
        data = pd.DataFrame({
            'date': dates,
            'open': base_price + np.random.randn(500) * 0.5,
            'high': base_price + np.abs(np.random.randn(500)) * 1.5,
            'low': base_price - np.abs(np.random.randn(500)) * 1.5,
            'close': base_price + np.random.randn(500) * 0.3
        })
     
        # Ensure high is highest and low is lowest
        data['high'] = data[['open', 'high', 'close']].max(axis=1)
        data['low'] = data[['open', 'low', 'close']].min(axis=1)
     
        # Initialize and run the indicator
        indicator = GannPivotIndicator(gann_days=4, sig_expir=50)
        result = indicator.analyze(data)
     
        # Plot results
        indicator.plot_signals(data, result)
     
        # Print statistics
        stats = indicator.get_pivot_statistics()
        print("\nGann Pivot Indicator Statistics:")
        for key, value in stats.items():
            print(f"{key}: {value}")
     
        # Show signals
        print("\nBuy Signals:")
        for date, price in indicator.buy_signals[:5]:  # Show first 5
            print(f"  {date}: ${price:.2f}")
         
        print("\nSell Signals:")
        for date, price in indicator.sell_signals[:5]:  # Show first 5
            print(f"  {date}: ${price:.2f}")



    [​IMG]

    W.D. Gann's Swing Trading Methods
    Historical Background

    W.D. Gann originally developed a 3-day swing chart method documented in his June 1933 course "The Mechanical Method And Trend Indicator For Trading Grains." However, in early 1955 prior to his death, Gann made handwritten alterations noting: "Use two-day charts and rules better than three day," with his signature.

    Core Principles of Gann Swing Charts

    1. Three-Day Swing Chart Rules (Original Method)
    The trend line has to move in 3 up days consecutively, to qualify for an uptrend. Gann Rules for Swing Trading - Bramesh's Technical Analysis +2 The basic rules are:




      • Downswing: Three consecutive days of higher highs are needed to form a swing high in a downtrend
      • According to W.D. Gann, 3 consecutive down candles must occur before the line "swings" to the bottom of the 3rd down candle
    2. Two-Day Swing Chart Rules (Revised Method)

    The swing direction can change to up only if the market makes two consecutive higher highs, and the swing direction can change to down only if the market makes two consecutive lower lows. This method is more responsive to market changes.

    3. One-Day Swing Charts

    While less common, 1-day swing charts follow similar principles but react to every new high or low, making them extremely sensitive to price movements.

    Key Swing Trading Rules

    Bar Types and Classifications

    Up Day: This occurs when the asset's price reaches a higher high and a higher low than the previous day Down Day: A down day is when the asset's price forms a lower high and a lower low compared to the prior day Inside Day: This is when the asset's price shows a lower high and a higher low than the previous day Outside Day: An outside day occurs when the asset's price breaks the range of the previous day by forming both a higher high and a lower low Gann Swing Charts | FXTM

    Trading Applications

    Trend Identification



      • Uptrend: Trend Change from Down to Up. Prices must take out the nearest peak, and the trend was previously down
      • Downtrend: Trend Change from Up to Down. Prices must take out the nearest valley and the trend was previously up
    Support and Resistance



      • Support: Support Is the Valley of the Previous Clearly Defined Swing
      • Resistance: Resistance Is the Peak of the Previous Clearly Defined Swing
    Modified Modern Approach

    Some traders have modified the traditional Gann 3 period swing chart by relaxing the requirement for there to be 3 "consecutive" days in order for a Gann swing to be formed, using instead "3 lower lows (without there being a new higher high in-between)."

    Practical Trading Rules

    According to Gann Rules for Swing Trading Gann Rules for Swing Trading - Bramesh's Technical Analysis:




    Key Benefits

    The main goal of using Gann's charts is to remove the "noise" from the price charts, which is not only unnecessary but also obscures the interpretation of the price action FXTMChartalert

    The choice between 1, 2, or 3-day swing charts depends on your trading style:




      • 1-day: Most sensitive, suitable for very short-term trading
      • 2-day: Gann's preferred method later in life, good balance
      • 3-day: Original method, filters out more noise, better for position trading
     
    Last edited: Aug 2, 2025 at 8:48 PM
    semperfrosty and Sekiyo like this.
  2. Sekiyo

    Sekiyo

    Last edited: Aug 2, 2025 at 8:41 PM
    MarkBrown likes this.
  3. MarkBrown

    MarkBrown


    INDICATOR

    Code:
    //@version=5
    indicator("Gann Pivot Indicator", overlay=true, max_bars_back=1500)
    
    // =====================================================================
    // GANN PIVOT INDICATOR
    //
    // Pine Script Translation for TradingView
    //
    // Use in conjunction with the Gann Pivot Trading System
    // =====================================================================
    
    // Input Parameters
    gannDays = input.int(4, "Gann Days", minval=1, tooltip="Minimum number of days required between pivots for a valid signal")
    sigExpir = input.int(50, "Signal Expiration", minval=1, tooltip="How many bars a signal remains valid")
    showPivots = input.bool(true, "Show Pivot Points", tooltip="Display pivot highs and lows on chart")
    showBuyZone = input.bool(true, "Show Buy Signal Zone", tooltip="Highlight buy signal zones")
    showSellZone = input.bool(true, "Show Sell Signal Zone", tooltip="Highlight sell signal zones")
    
    // Colors
    buyColor = input.color(color.green, "Buy Signal Color")
    sellColor = input.color(color.red, "Sell Signal Color")
    pivotHighColor = input.color(color.blue, "Pivot High Color")
    pivotLowColor = input.color(color.orange, "Pivot Low Color")
    
    // Variables for tracking pivots
    var float marketHigh = -999999.0
    var float marketLow = 999999.0
    
    // Arrays to store pivot data (Pine Script handles array bounds automatically)
    var pivotHighBars = array.new_int(1500)
    var pivotHighPrices = array.new_float(1500)
    var pivotLowBars = array.new_int(1500)
    var pivotLowPrices = array.new_float(1500)
    
    // Pivot counters
    var int phiCount = 0
    var int ploCount = 0
    
    // Signal variables
    var float tempBuyPrice = 0.0
    var int tempBuyBar = 0
    var bool tempBuyOn = false
    
    var float tempSellPrice = 0.0
    var int tempSellBar = 0
    var bool tempSellOn = false
    
    // Track market extremes
    if high > marketHigh
        marketHigh := high
    if low < marketLow
        marketLow := low
    
    // Function to add pivot high with array management
    addPivotHigh(bar, price) =>
        if phiCount < 1500
            array.set(pivotHighBars, phiCount, bar)
            array.set(pivotHighPrices, phiCount, price)
            phiCount := phiCount + 1
        else
            // Shift array elements
            for i = 0 to 1498
                array.set(pivotHighBars, i, array.get(pivotHighBars, i + 1))
                array.set(pivotHighPrices, i, array.get(pivotHighPrices, i + 1))
            array.set(pivotHighBars, 1499, bar)
            array.set(pivotHighPrices, 1499, price)
    
    // Function to add pivot low with array management
    addPivotLow(bar, price) =>
        if ploCount < 1500
            array.set(pivotLowBars, ploCount, bar)
            array.set(pivotLowPrices, ploCount, price)
            ploCount := ploCount + 1
        else
            // Shift array elements
            for i = 0 to 1498
                array.set(pivotLowBars, i, array.get(pivotLowBars, i + 1))
                array.set(pivotLowPrices, i, array.get(pivotLowPrices, i + 1))
            array.set(pivotLowBars, 1499, bar)
            array.set(pivotLowPrices, 1499, price)
    
    // Identify Pivot Highs (3-bar pattern)
    isPivotHigh = high < high[1] and high[1] > high[2]
    if isPivotHigh
        addPivotHigh(bar_index - 1, high[1])
        if showPivots
            label.new(bar_index - 1, high[1], "PH", color=pivotHighColor, style=label.style_circle, size=size.tiny)
    
    // Identify Pivot Lows (3-bar pattern)
    isPivotLow = low > low[1] and low[1] < low[2]
    if isPivotLow
        addPivotLow(bar_index - 1, low[1])
        if showPivots
            label.new(bar_index - 1, low[1], "PL", color=pivotLowColor, style=label.style_circle, size=size.tiny)
    
    // Check for Buy Setup
    checkBuySetup() =>
        if phiCount > 1 and ploCount > 0
            latestPHBar = array.get(pivotHighBars, phiCount - 1)
            latestPHPrice = array.get(pivotHighPrices, phiCount - 1)
      
            // Check if this is a recent pivot high and not at market high
            if latestPHBar == bar_index - 1 and latestPHPrice < marketHigh
                prevHigherBar = -1
          
                // Find previous higher pivot high
                for i = phiCount - 2 to 0
                    if array.get(pivotHighPrices, i) > latestPHPrice
                        prevHigherBar := array.get(pivotHighBars, i)
                        break
          
                if prevHigherBar != -1
                    barCount = latestPHBar - prevHigherBar
              
                    if barCount >= gannDays
                        // Find lowest pivot low between the two highs
                        lowestPLo = 999999.0
                        lowestPLoBar = -1
                  
                        for i = 0 to ploCount - 1
                            ploBar = array.get(pivotLowBars, i)
                            if ploBar > prevHigherBar and ploBar < latestPHBar
                                ploPrice = array.get(pivotLowPrices, i)
                                if ploPrice < lowestPLo
                                    lowestPLo := ploPrice
                                    lowestPLoBar := ploBar
                  
                        if lowestPLoBar != -1
                            lo2HiDays = latestPHBar - lowestPLoBar
                      
                            if lo2HiDays >= gannDays and latestPHBar > tempBuyBar
                                tempBuyPrice := latestPHPrice
                                tempBuyBar := latestPHBar
                                tempBuyOn := true
    
    // Check for Sell Setup
    checkSellSetup() =>
        if ploCount > 1 and phiCount > 0
            latestPLBar = array.get(pivotLowBars, ploCount - 1)
            latestPLPrice = array.get(pivotLowPrices, ploCount - 1)
      
            // Check if this is a recent pivot low and not at market low
            if latestPLBar == bar_index - 1 and latestPLPrice > marketLow
                prevLowerBar = -1
                barCount = 0
          
                // Find previous lower pivot low
                for i = ploCount - 2 to 0
                    if array.get(pivotLowPrices, i) < latestPLPrice
                        prevLowerBar := array.get(pivotLowBars, i)
                        barCount := latestPLBar - prevLowerBar
                        break
          
                if prevLowerBar != -1 and barCount >= gannDays
                    // Find highest pivot high between the two lows
                    highestPHi = -999999.0
                    highestPHiBar = -1
              
                    for i = 0 to phiCount - 1
                        phiBar = array.get(pivotHighBars, i)
                        if phiBar > prevLowerBar and phiBar < latestPLBar
                            phiPrice = array.get(pivotHighPrices, i)
                            if phiPrice > highestPHi
                                highestPHi := phiPrice
                                highestPHiBar := phiBar
              
                    if highestPHiBar != -1
                        hi2LoDays = latestPLBar - highestPHiBar
                  
                        if hi2LoDays >= gannDays and latestPLBar > tempSellBar
                            tempSellPrice := latestPLPrice
                            tempSellBar := latestPLBar
                            tempSellOn := true
    
    // Run setup checks
    checkBuySetup()
    checkSellSetup()
    
    // Handle Buy Signals
    buySignalPrice = float(na)
    if tempBuyOn
        if high < tempBuyPrice and bar_index - tempBuyBar <= sigExpir
            buySignalPrice := tempBuyPrice + syminfo.mintick
        else
            tempBuyOn := false
    
    // Handle Sell Signals
    sellSignalPrice = float(na)
    if tempSellOn
        if low > tempSellPrice and bar_index - tempSellBar <= sigExpir
            sellSignalPrice := tempSellPrice - syminfo.mintick
        else
            tempSellOn := false
    
    // Plot buy and sell signals
    plotshape(not na(buySignalPrice), title="Buy Signal", location=location.absolute,
             style=shape.triangleup, size=size.small, color=buyColor, text="BUY")
        
    plotshape(not na(sellSignalPrice), title="Sell Signal", location=location.absolute,
             style=shape.triangledown, size=size.small, color=sellColor, text="SELL")
    
    // Draw signal zones (optional visual enhancement)
    if showBuyZone and not na(buySignalPrice)
        box.new(bar_index - 1, buySignalPrice * 0.999, bar_index + 5, buySignalPrice * 1.001,
                border_color=buyColor, bgcolor=color.new(buyColor, 90))
    
    if showSellZone and not na(sellSignalPrice)
        box.new(bar_index - 1, sellSignalPrice * 0.999, bar_index + 5, sellSignalPrice * 1.001,
                border_color=sellColor, bgcolor=color.new(sellColor, 90))
    
    // Plot signal levels as lines
    plot(tempBuyOn ? tempBuyPrice + syminfo.mintick : na, title="Buy Level",
         color=buyColor, style=plot.style_linebr, linewidth=2)
    
    plot(tempSellOn ? tempSellPrice - syminfo.mintick : na, title="Sell Level",
         color=sellColor, style=plot.style_linebr, linewidth=2)
    
    // Add alerts
    alertcondition(not na(buySignalPrice), title="Gann Buy Signal", message="Gann Pivot Buy Signal at {{close}}")
    alertcondition(not na(sellSignalPrice), title="Gann Sell Signal", message="Gann Pivot Sell Signal at {{close}}")
    
    // Display information panel
    var table infoTable = table.new(position.top_right, 2, 5, bgcolor=color.new(color.black, 80))
    if barstate.islast
        table.cell(infoTable, 0, 0, "Gann Days:", text_color=color.white, text_size=size.small)
        table.cell(infoTable, 1, 0, str.tostring(gannDays), text_color=color.white, text_size=size.small)
        table.cell(infoTable, 0, 1, "Signal Expiry:", text_color=color.white, text_size=size.small)
        table.cell(infoTable, 1, 1, str.tostring(sigExpir), text_color=color.white, text_size=size.small)
        table.cell(infoTable, 0, 2, "Pivot Highs:", text_color=color.white, text_size=size.small)
        table.cell(infoTable, 1, 2, str.tostring(phiCount), text_color=color.white, text_size=size.small)
        table.cell(infoTable, 0, 3, "Pivot Lows:", text_color=color.white, text_size=size.small)
        table.cell(infoTable, 1, 3, str.tostring(ploCount), text_color=color.white, text_size=size.small)
        table.cell(infoTable, 0, 4, "Active:", text_color=color.white, text_size=size.small)
        status = tempBuyOn ? "BUY" : tempSellOn ? "SELL" : "NONE"
        statusColor = tempBuyOn ? buyColor : tempSellOn ? sellColor : color.gray
        table.cell(infoTable, 1, 4, status, text_color=statusColor, text_size=size.small)

    SYSTEM

    Code:
    //@version=5
    strategy("Gann Pivot Trading System",
             overlay=true,
             initial_capital=100000,
             default_qty_type=strategy.percent_of_equity,
             default_qty_value=10,
             commission_type=strategy.commission.percent,
             commission_value=0.05,
             max_bars_back=1500)
    
    // =====================================================================
    // GANN PIVOT TRADING SYSTEM
    // Based on C.T.C.R.'s GANN PIVOT INDICATOR by Roger D. Rines
    // Complete Trading System with Risk Management
    // =====================================================================
    
    // Strategy Inputs
    group1 = "Gann Settings"
    gannDays = input.int(4, "Gann Days", minval=1, group=group1, tooltip="Minimum days between pivots for valid signal")
    sigExpir = input.int(50, "Signal Expiration", minval=1, group=group1, tooltip="How many bars a signal remains valid")
    
    group2 = "Position Sizing"
    useFixedSize = input.bool(true, "Use Fixed Position Size", group=group2)
    fixedContracts = input.int(1, "Fixed Contracts", minval=1, group=group2)
    riskPercent = input.float(1.0, "Risk % Per Trade", minval=0.1, maxval=10, step=0.1, group=group2)
    
    group3 = "Risk Management"
    useStopLoss = input.bool(true, "Use Stop Loss", group=group3)
    stopLossType = input.string("Fixed Points", "Stop Loss Type", options=["Fixed Points", "ATR", "Pivot Based"], group=group3)
    stopLossPoints = input.float(2.0, "Stop Loss Points", minval=0.1, group=group3)
    stopLossATR = input.float(2.0, "Stop Loss ATR Multiplier", minval=0.1, group=group3)
    
    useProfitTarget = input.bool(true, "Use Profit Target", group=group3)
    profitTargetType = input.string("Fixed Points", "Profit Target Type", options=["Fixed Points", "ATR", "Risk Multiple"], group=group3)
    profitTargetPoints = input.float(4.0, "Profit Target Points", minval=0.1, group=group3)
    profitTargetATR = input.float(3.0, "Profit Target ATR Multiplier", minval=0.1, group=group3)
    profitTargetMultiple = input.float(2.0, "Risk/Reward Ratio", minval=0.5, maxval=10, step=0.5, group=group3)
    
    useTrailingStop = input.bool(false, "Use Trailing Stop", group=group3)
    trailingType = input.string("Fixed Points", "Trailing Stop Type", options=["Fixed Points", "ATR", "Pivot Based"], group=group3)
    trailingPoints = input.float(2.0, "Trailing Stop Points", minval=0.1, group=group3)
    trailingATR = input.float(1.5, "Trailing Stop ATR Multiplier", minval=0.1, group=group3)
    
    group4 = "Time Filters"
    useTimeFilter = input.bool(false, "Use Time Filter", group=group4)
    startHour = input.int(9, "Start Hour", minval=0, maxval=23, group=group4)
    startMinute = input.int(30, "Start Minute", minval=0, maxval=59, group=group4)
    endHour = input.int(15, "End Hour", minval=0, maxval=23, group=group4)
    endMinute = input.int(0, "End Minute", minval=0, maxval=59, group=group4)
    exitHour = input.int(15, "Exit Hour", minval=0, maxval=23, group=group4)
    exitMinute = input.int(45, "Exit Minute", minval=0, maxval=59, group=group4)
    
    group5 = "Additional Filters"
    useMAFilter = input.bool(false, "Use MA Filter", group=group5)
    maLength = input.int(50, "MA Length", minval=1, group=group5)
    minVolume = input.int(100000, "Minimum Volume", minval=0, group=group5)
    maxDailyTrades = input.int(5, "Max Daily Trades", minval=1, group=group5)
    
    group6 = "Visual Settings"
    showPivots = input.bool(true, "Show Pivot Points", group=group6)
    showSignals = input.bool(true, "Show Entry Signals", group=group6)
    showLevels = input.bool(true, "Show Stop/Target Levels", group=group6)
    showDashboard = input.bool(true, "Show Info Dashboard", group=group6)
    
    // Colors
    buyColor = input.color(color.green, "Buy Signal Color", group=group6)
    sellColor = input.color(color.red, "Sell Signal Color", group=group6)
    pivotHighColor = input.color(color.blue, "Pivot High Color", group=group6)
    pivotLowColor = input.color(color.orange, "Pivot Low Color", group=group6)
    
    // Variables
    var float marketHigh = -999999.0
    var float marketLow = 999999.0
    
    // Arrays for pivot storage
    var pivotHighBars = array.new_int(1500)
    var pivotHighPrices = array.new_float(1500)
    var pivotLowBars = array.new_int(1500)
    var pivotLowPrices = array.new_float(1500)
    
    // Pivot counters
    var int phiCount = 0
    var int ploCount = 0
    
    // Signal variables
    var float tempBuyPrice = 0.0
    var int tempBuyBar = 0
    var bool tempBuyOn = false
    
    var float tempSellPrice = 0.0
    var int tempSellBar = 0
    var bool tempSellOn = false
    
    // Trading variables
    var int tradesToday = 0
    var float entryPrice = 0.0
    var float stopPrice = 0.0
    var float targetPrice = 0.0
    var float trailingStopPrice = 0.0
    var bool isTrailing = false
    
    // Performance tracking
    var int consecutiveWins = 0
    var int consecutiveLosses = 0
    var float maxDrawdown = 0.0
    var float equity = 100000.0
    var float peakEquity = 100000.0
    
    // Calculate indicators
    atrValue = ta.atr(14)
    maValue = useMAFilter ? ta.sma(close, maLength) : close
    
    // Time functions
    isWithinTime() =>
        if useTimeFilter
            currentTime = hour * 100 + minute
            startTime = startHour * 100 + startMinute
            endTime = endHour * 100 + endMinute
            currentTime >= startTime and currentTime <= endTime
        else
            true
    
    shouldExitTime() =>
        if useTimeFilter
            currentTime = hour * 100 + minute
            exitTime = exitHour * 100 + exitMinute
            currentTime >= exitTime
        else
            false
    
    // Reset daily counters
    if dayofmonth != dayofmonth[1]
        tradesToday := 0
    
    // Track market extremes
    if high > marketHigh
        marketHigh := high
      
    if low < marketLow
        marketLow := low
    
    // Function to add pivot high
    addPivotHigh(bar, price) =>
        if phiCount < 1500
            array.set(pivotHighBars, phiCount, bar)
            array.set(pivotHighPrices, phiCount, price)
            phiCount := phiCount + 1
        else
            for i = 0 to 1498
                array.set(pivotHighBars, i, array.get(pivotHighBars, i + 1))
                array.set(pivotHighPrices, i, array.get(pivotHighPrices, i + 1))
            array.set(pivotHighBars, 1499, bar)
            array.set(pivotHighPrices, 1499, price)
    
    // Function to add pivot low
    addPivotLow(bar, price) =>
        if ploCount < 1500
            array.set(pivotLowBars, ploCount, bar)
            array.set(pivotLowPrices, ploCount, price)
            ploCount := ploCount + 1
        else
            for i = 0 to 1498
                array.set(pivotLowBars, i, array.get(pivotLowBars, i + 1))
                array.set(pivotLowPrices, i, array.get(pivotLowPrices, i + 1))
            array.set(pivotLowBars, 1499, bar)
            array.set(pivotLowPrices, 1499, price)
    
    // Identify Pivot Highs
    isPivotHigh = high < high[1] and high[1] > high[2]
    if isPivotHigh
        addPivotHigh(bar_index - 1, high[1])
        if showPivots
            label.new(bar_index - 1, high[1], "PH", color=pivotHighColor,
                     style=label.style_circle, size=size.tiny)
    
    // Identify Pivot Lows
    isPivotLow = low > low[1] and low[1] < low[2]
    if isPivotLow
        addPivotLow(bar_index - 1, low[1])
        if showPivots
            label.new(bar_index - 1, low[1], "PL", color=pivotLowColor,
                     style=label.style_circle, size=size.tiny)
    
    // Check for Buy Setup
    checkBuySetup() =>
        if phiCount > 1 and ploCount > 0
            latestPHBar = array.get(pivotHighBars, phiCount - 1)
            latestPHPrice = array.get(pivotHighPrices, phiCount - 1)
          
            if latestPHBar == bar_index - 1 and latestPHPrice < marketHigh
                prevHigherBar = -1
              
                for i = phiCount - 2 to 0
                    if array.get(pivotHighPrices, i) > latestPHPrice
                        prevHigherBar := array.get(pivotHighBars, i)
                        break
              
                if prevHigherBar != -1
                    barCount = latestPHBar - prevHigherBar
                  
                    if barCount >= gannDays
                        lowestPLo = 999999.0
                        lowestPLoBar = -1
                      
                        for i = 0 to ploCount - 1
                            ploBar = array.get(pivotLowBars, i)
                            if ploBar > prevHigherBar and ploBar < latestPHBar
                                ploPrice = array.get(pivotLowPrices, i)
                                if ploPrice < lowestPLo
                                    lowestPLo := ploPrice
                                    lowestPLoBar := ploBar
                      
                        if lowestPLoBar != -1
                            lo2HiDays = latestPHBar - lowestPLoBar
                          
                            if lo2HiDays >= gannDays and latestPHBar > tempBuyBar
                                tempBuyPrice := latestPHPrice
                                tempBuyBar := latestPHBar
                                tempBuyOn := true
    
    // Check for Sell Setup
    checkSellSetup() =>
        if ploCount > 1 and phiCount > 0
            latestPLBar = array.get(pivotLowBars, ploCount - 1)
            latestPLPrice = array.get(pivotLowPrices, ploCount - 1)
          
            if latestPLBar == bar_index - 1 and latestPLPrice > marketLow
                prevLowerBar = -1
                barCount = 0
              
                for i = ploCount - 2 to 0
                    if array.get(pivotLowPrices, i) < latestPLPrice
                        prevLowerBar := array.get(pivotLowBars, i)
                        barCount := latestPLBar - prevLowerBar
                        break
              
                if prevLowerBar != -1 and barCount >= gannDays
                    highestPHi = -999999.0
                    highestPHiBar = -1
                  
                    for i = 0 to phiCount - 1
                        phiBar = array.get(pivotHighBars, i)
                        if phiBar > prevLowerBar and phiBar < latestPLBar
                            phiPrice = array.get(pivotHighPrices, i)
                            if phiPrice > highestPHi
                                highestPHi := phiPrice
                                highestPHiBar := phiBar
                  
                    if highestPHiBar != -1
                        hi2LoDays = latestPLBar - highestPHiBar
                      
                        if hi2LoDays >= gannDays and latestPLBar > tempSellBar
                            tempSellPrice := latestPLPrice
                            tempSellBar := latestPLBar
                            tempSellOn := true
    
    // Run setup checks
    checkBuySetup()
    checkSellSetup()
    
    // Position sizing calculation
    calculatePositionSize() =>
        if useFixedSize
            fixedContracts
        else
            riskAmount = strategy.equity * (riskPercent / 100)
            stopDistance = stopLossType == "Fixed Points" ? stopLossPoints :
                          stopLossType == "ATR" ? atrValue * stopLossATR :
                          close * 0.02  // Default 2% for pivot based
            contracts = math.floor(riskAmount / (stopDistance * syminfo.pointvalue))
            math.max(1, contracts)
    
    // Entry Conditions
    canTrade = isWithinTime() and tradesToday < maxDailyTrades and volume >= minVolume
    
    // Long Entry
    longCondition = strategy.position_size == 0 and canTrade and tempBuyOn and
                    high < tempBuyPrice and bar_index - tempBuyBar <= sigExpir and
                    (not useMAFilter or close > maValue)
    
    if longCondition
        posSize = calculatePositionSize()
        strategy.entry("Long", strategy.long, qty=posSize, stop=tempBuyPrice + syminfo.mintick)
        tempBuyOn := false
        tradesToday += 1
    
    // Short Entry
    shortCondition = strategy.position_size == 0 and canTrade and tempSellOn and
                     low > tempSellPrice and bar_index - tempSellBar <= sigExpir and
                     (not useMAFilter or close < maValue)
    
    if shortCondition
        posSize = calculatePositionSize()
        strategy.entry("Short", strategy.short, qty=posSize, stop=tempSellPrice - syminfo.mintick)
        tempSellOn := false
        tradesToday += 1
    
    // Position Management
    if strategy.position_size != 0
        isLong = strategy.position_size > 0
        isShort = strategy.position_size < 0
      
        // Initialize on entry
        if strategy.position_size != strategy.position_size[1]
            entryPrice := strategy.position_avg_price
            isTrailing := false
          
            // Calculate stop loss
            if useStopLoss
                if stopLossType == "Fixed Points"
                    stopPrice := isLong ? entryPrice - stopLossPoints : entryPrice + stopLossPoints
                else if stopLossType == "ATR"
                    stopPrice := isLong ? entryPrice - (atrValue * stopLossATR) : entryPrice + (atrValue * stopLossATR)
                else if stopLossType == "Pivot Based"
                    if isLong and ploCount > 0
                        stopPrice := array.get(pivotLowPrices, ploCount - 1) - syminfo.mintick
                    else if isShort and phiCount > 0
                        stopPrice := array.get(pivotHighPrices, phiCount - 1) + syminfo.mintick
          
            // Calculate profit target
            if useProfitTarget
                riskAmount = math.abs(entryPrice - stopPrice)
              
                if profitTargetType == "Fixed Points"
                    targetPrice := isLong ? entryPrice + profitTargetPoints : entryPrice - profitTargetPoints
                else if profitTargetType == "ATR"
                    targetPrice := isLong ? entryPrice + (atrValue * profitTargetATR) : entryPrice - (atrValue * profitTargetATR)
                else if profitTargetType == "Risk Multiple"
                    targetPrice := isLong ? entryPrice + (riskAmount * profitTargetMultiple) :
                                  entryPrice - (riskAmount * profitTargetMultiple)
      
        // Trailing Stop Logic
        if useTrailingStop
            newTrailStop = 0.0
          
            if trailingType == "Fixed Points"
                newTrailStop := isLong ? high - trailingPoints : low + trailingPoints
            else if trailingType == "ATR"
                newTrailStop := isLong ? high - (atrValue * trailingATR) : low + (atrValue * trailingATR)
            else if trailingType == "Pivot Based"
                if isLong and ploCount > 0
                    newTrailStop := array.get(pivotLowPrices, ploCount - 1) - syminfo.mintick
                else if isShort and phiCount > 0
                    newTrailStop := array.get(pivotHighPrices, phiCount - 1) + syminfo.mintick
          
            if isLong and newTrailStop > stopPrice
                stopPrice := newTrailStop
                isTrailing := true
            else if isShort and newTrailStop < stopPrice
                stopPrice := newTrailStop
                isTrailing := true
      
        // Execute stops and targets
        if useStopLoss
            strategy.exit("Exit", stop=stopPrice, limit=useProfitTarget ? targetPrice : na)
        else if useProfitTarget
            strategy.exit("Exit", limit=targetPrice)
    
    // Time-based exit
    if shouldExitTime() and strategy.position_size != 0
        strategy.close_all("EOD Exit")
    
    // Plotting
    // Signal levels
    plot(showSignals and tempBuyOn ? tempBuyPrice + syminfo.mintick : na,
         "Buy Level", buyColor, 2, plot.style_linebr)
    plot(showSignals and tempSellOn ? tempSellPrice - syminfo.mintick : na,
         "Sell Level", sellColor, 2, plot.style_linebr)
    
    // Stop and target levels
    plot(showLevels and strategy.position_size != 0 ? stopPrice : na,
         "Stop Level", color.red, 1, plot.style_linebr)
    plot(showLevels and strategy.position_size != 0 and useProfitTarget ? targetPrice : na,
         "Target Level", color.green, 1, plot.style_linebr)
    
    // Entry signals
    plotshape(showSignals and longCondition, "Long Signal", shape.triangleup,
             location.belowbar, buyColor, size=size.small)
    plotshape(showSignals and shortCondition, "Short Signal", shape.triangledown,
             location.abovebar, sellColor, size=size.small)
    
    // Dashboard
    if showDashboard
        var table dashboard = table.new(position.top_right, 2, 10, bgcolor=color.new(color.black, 80))
      
        if barstate.islast
            // Headers
            table.cell(dashboard, 0, 0, "Metric", text_color=color.white, bgcolor=color.new(color.blue, 50))
            table.cell(dashboard, 1, 0, "Value", text_color=color.white, bgcolor=color.new(color.blue, 50))
          
            // Settings
            table.cell(dashboard, 0, 1, "Gann Days", text_color=color.white)
            table.cell(dashboard, 1, 1, str.tostring(gannDays), text_color=color.white)
          
            table.cell(dashboard, 0, 2, "Signal Expiry", text_color=color.white)
            table.cell(dashboard, 1, 2, str.tostring(sigExpir), text_color=color.white)
          
            // Pivot counts
            table.cell(dashboard, 0, 3, "Pivot Highs", text_color=color.white)
            table.cell(dashboard, 1, 3, str.tostring(phiCount), text_color=color.white)
          
            table.cell(dashboard, 0, 4, "Pivot Lows", text_color=color.white)
            table.cell(dashboard, 1, 4, str.tostring(ploCount), text_color=color.white)
          
            // Trading status
            table.cell(dashboard, 0, 5, "Position", text_color=color.white)
            posText = strategy.position_size > 0 ? "LONG" :
                      strategy.position_size < 0 ? "SHORT" : "FLAT"
            posColor = strategy.position_size > 0 ? buyColor :
                       strategy.position_size < 0 ? sellColor : color.gray
            table.cell(dashboard, 1, 5, posText, text_color=posColor)
          
            // Signals
            table.cell(dashboard, 0, 6, "Active Signal", text_color=color.white)
            sigText = tempBuyOn ? "BUY" : tempSellOn ? "SELL" : "NONE"
            sigColor = tempBuyOn ? buyColor : tempSellOn ? sellColor : color.gray
            table.cell(dashboard, 1, 6, sigText, text_color=sigColor)
          
            // Daily trades
            table.cell(dashboard, 0, 7, "Trades Today", text_color=color.white)
            table.cell(dashboard, 1, 7, str.tostring(tradesToday) + "/" + str.tostring(maxDailyTrades),
                      text_color=color.white)
          
            // Performance
            table.cell(dashboard, 0, 8, "Net Profit", text_color=color.white)
            netProfit = strategy.netprofit
            profitColor = netProfit >= 0 ? color.green : color.red
            table.cell(dashboard, 1, 8, "$" + str.tostring(netProfit, "#,###.##"), text_color=profitColor)
          
            // Win rate
            table.cell(dashboard, 0, 9, "Win Rate", text_color=color.white)
            winRate = strategy.wintrades / math.max(strategy.closedtrades, 1) * 100
            table.cell(dashboard, 1, 9, str.tostring(winRate, "#.#") + "%", text_color=color.white)
    
    // Alerts
    alertcondition(longCondition, "Long Entry", "Gann Pivot Long Signal at {{close}}")
    alertcondition(shortCondition, "Short Entry", "Gann Pivot Short Signal at {{close}}")
    alertcondition(strategy.position_size != 0 and useStopLoss and
                  ((strategy.position_size > 0 and low <= stopPrice) or
                   (strategy.position_size < 0 and high >= stopPrice)),
                  "Stop Hit", "Stop Loss Hit at {{close}}")
    alertcondition(strategy.position_size != 0 and useProfitTarget and
                  ((strategy.position_size > 0 and high >= targetPrice) or
                   (strategy.position_size < 0 and low <= targetPrice)),
                  "Target Hit", "Profit Target Hit at {{close}}")


    Key Features of the TradingView Version:
    1. Visual Enhancements
    • Pivot points marked with small circles (PH/PL)
    • Buy/sell signals shown as triangles with text
    • Optional signal zones (colored boxes)
    • Signal levels drawn as lines
    2. User-Friendly Inputs
    • Adjustable Gann Days and Signal Expiration
    • Toggle pivot display on/off
    • Customizable colors for all elements
    • Show/hide signal zones
    3. Information Panel
    • Real-time display of indicator statistics
    • Shows current active signals
    • Pivot count tracking
    4. Alerts
    • Built-in alert conditions for buy/sell signals
    • Can be connected to TradingView's alert system
    5. Pine Script Optimizations
    • Uses Pine Script v5 features
    • Efficient array handling
    • Proper NA value handling
    • Clean, maintainable code structure
    How to Use:
    1. Add to TradingView: Copy the code and paste into Pine Editor
    2. Save and Add to Chart: Click "Add to Chart"
    3. Configure Settings: Adjust parameters in the indicator settings
    4. Set Alerts: Right-click on chart → "Add Alert" → Choose Gann conditions
    5. Interpret Signals:
      • Green triangles = Buy signals
      • Red triangles = Sell signals
      • Blue dots = Pivot highs
      • Orange dots = Pivot lows
    The indicator faithfully reproduces the original logic while taking advantage of TradingView's visual capabilities for a better trading experience.
     
    Last edited: Aug 2, 2025 at 8:58 PM
    SunTrader and Sekiyo like this.
  4. ph1l

    ph1l

    MarkBrown and Sekiyo like this.
  5. themickey

    themickey

    Just another day of traders gravitating down TA rabbit hole nonsense.
     
  6. MarkBrown

    MarkBrown

    yep it's a bitch alright .... nothing works as good as watching cnn and msnbc i guess for your financial advice. maybe some suze orman or motley fools?
     
    themickey likes this.
  7. themickey

    themickey

    No no no, I get my best financial advice from Twumpy.
     
  8. MarkBrown

    MarkBrown

    then stop your bitching and enjoy the ride.
     
    themickey likes this.
  9. themickey

    themickey

    Riiiiiight
    Fuckin genius oright....
     
  10. deaddog

    deaddog

    The Gann indicator is based on historical price and time data.
    Price moves the Gann indicator, not the other way around.
    Risk control in more important than the indicator.