Overall Statistics
Total Trades
0
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Net Profit
0%
Sharpe Ratio
0
Probabilistic Sharpe Ratio
0%
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0
Beta
0
Annual Standard Deviation
0
Annual Variance
0
Information Ratio
-0.585
Tracking Error
0.153
Treynor Ratio
0
Total Fees
$0.00
Estimated Strategy Capacity
$0
Lowest Capacity Asset
Portfolio Turnover
0%
"""  
Algo Overview: 

Use the Hurst Exponent to quantify wheteher gold has been trending or mean reverting.
    - run over different lengths and timeframes to see how it is changing. 
        - 

How does the change in periods affect HE? Are shorter periods more mean reverting than longer lookback periods akin to SPX? 



"""
''' 
Explanation: https://blog.quantinsti.com/hurst-exponent/#:~:text=Hurst%20Exponent%20Definition,between%20pairs%20of%20values%20increases
    - > 0.5 = trending | < 0.5 = sideways market | = 0.5 = random walk where prediction of futre based on past dat is not possible


Hurst python example: https://www.quantconnect.com/forum/discussion/14875/hurst-exponent-function/p1
    accompaning YT video by author: https://www.youtube.com/watch?v=IbfplwDAMik 

    Steps:
        1) create rolling window called self.closingPrices (python list of closing prices in a rolling window) 
        2) 

Hurst Exponent ex: https://www.quantconnect.com/forum/discussion/1695/hurst-exponent-indicator/p


Next Steps:

Build out for other time frames and hurst_periods

test other markets
'''


# region imports
from AlgorithmImports import *
import numpy as np

# endregion

FUTURES_CONTRACT = Futures.Indices.SP500EMini
# FUTURES_CONTRACT = Futures.Metals.MicroGold

HURST_PERIODS = 276

class DeterminedYellowGreenRabbit(QCAlgorithm):

    def Initialize(self):
        # Debug Set
        # self.SetStartDate(2023,1,1)   
        # self.SetEndDate(2023,7,10)
        
        # Long Set
        self.SetStartDate(2015,1,1)   
        self.SetEndDate(2023,7,10)

        # Long Set 2
        # self.SetStartDate(2016,1,1)   
        # self.SetEndDate(2020,1,1) 

        self.SetCash(50000)

        self.equity = self.AddEquity("GLD", Resolution.Minute, extendedMarketHours=False)
        self.Schedule.On(self.DateRules.EveryDay("GLD"), self.TimeRules.BeforeMarketClose(self.equity.Symbol, 0), self.marketClose)


        self.gc = self.AddFuture(FUTURES_CONTRACT, dataNormalizationMode = DataNormalizationMode.BackwardsPanamaCanal, dataMappingMode = DataMappingMode.OpenInterest, contractDepthOffset = 0, extendedMarketHours=True)
        consolidator = TradeBarConsolidator(timedelta(minutes=5))
        consolidator.DataConsolidated += self.OnDataConsolidated
        self.SubscriptionManager.AddConsolidator(self.gc.Symbol, consolidator)

        hurst_periods = self.GetParameter("hurst_periods")                            
        self.hurst_periods = HURST_PERIODS if hurst_periods is None else float(hurst_periods)

        self.closingPricesRW = RollingWindow[float](self.hurst_periods)

        self.closingPrices = []

        # Vizualization Vars
        HurstChart = Chart("Hurst Exponent")
        HurstChart.AddSeries(Series("Hurst", SeriesType.Line, 0))
        HurstChart.AddSeries(Series("Midpoint", SeriesType.Line, 0))
        self.AddChart(HurstChart)

        priceChart = Chart("Price Chart")
        priceChart.AddSeries(Series("Futures Price", SeriesType.Line, 0))
        self.AddChart(priceChart)

        # Initializaiton Vars
        self.HE = None

    def OnData(self, data: Slice):
        self.futuresPrice = self.gc.Price

    def OnDataConsolidated(self, sender, bar):

        # self.Debug(f"{self.Time} Close Price: {bar.Close}") 

        self.closingPricesRW.Add(bar.Close)

        if self.closingPricesRW.IsReady:
            # Convert closingPricesRW into a list
            for n in self.closingPricesRW:
                self.closingPrices.append(n)
            # self.Debug(f"{self.Time} closingPrices List: {self.closingPrices}")

            # Calculate Hurst Exponent
            self.HE = self.HurstExponent()
            # self.Debug(f"{self.Time} Hurst Exponent: {self.HE}")

            # # Chart
            # self.Plot("Hurst Exponent", "Hurst", self.HE)
            # self.Plot("Hurst Exponent", "Midpoint", 0.50)
            # self.Plot("Price Chart", "Futures Price", bar.Close)

            self.closingPrices = []

    def HurstExponent(self):
	#The Hurst Exponent is calculated using the Rescaled Range (R/S) analysis. The formula for the Hurst exponent is:
    # - The below calculation does not use the rescaled range but provides similar number
    
        #Hurst Exponent = (log(Rn/S) / log(n)) - 0.5
        #where Rn is the range of the cumulative sum of n data points and S is the standard deviation of 		the n data points
        # Generate vector of prices
        
        prices = np.array([self.closingPrices])
        
        # self.Debug(f"{self.Time} Couldn't calculate HE")
        
        # Calculate log returns
        Rn = np.cumsum(prices)
        S = np.std(prices)
        # Calculate Hurst exponent
        hurst = (np.log(Rn/S)) / np.log(prices) - 0.5
        # self.Debug(f"{self.Time} Hurst Exponent: {hurst}")
        return hurst[-1][-1]
        

    def marketClose(self):

        # Chart
        if self.HE is not None:
            self.Plot("Hurst Exponent", "Hurst", self.HE)
            self.Plot("Hurst Exponent", "Midpoint", 0.50)
            self.Plot("Price Chart", "Futures Price", self.futuresPrice)