Overall Statistics
Total Trades
28803
Average Win
0.06%
Average Loss
-0.06%
Compounding Annual Return
-3.321%
Drawdown
20.200%
Expectancy
-0.021
Net Profit
-18.275%
Sharpe Ratio
-0.335
Probabilistic Sharpe Ratio
0.005%
Loss Rate
52%
Win Rate
48%
Profit-Loss Ratio
1.06
Alpha
-0.021
Beta
-0.003
Annual Standard Deviation
0.063
Annual Variance
0.004
Information Ratio
-0.89
Tracking Error
0.163
Treynor Ratio
7.366
Total Fees
$53974.34
Estimated Strategy Capacity
$250000000.00
Lowest Capacity Asset
AXP R735QTJ8XC9X
#region imports
from AlgorithmImports import *
import math
#endregion


class MeanReversion(AlphaModel):
    def __init__(self):
        self.symbolData = []

        self.lastDay = -1

    def Update(self, algorithm, data):
        time = algorithm.Time
        day = algorithm.Time.day
        insights = []

        #Near the market close of each day
        for symbol in self.symbolData:
            isClosingSoon = algorithm.Securities[symbol].Exchange.IsClosingSoon(1)
            if isClosingSoon == True:
                break
            else:
                return insights
        
        if algorithm.Time.day == self.lastDay:
	        return insights
        self.lastDay = algorithm.Time.day


        startdate = time-timedelta(days=1)
        enddate = time

        history = algorithm.History(self.symbolData, startdate, enddate, Resolution.Minute)

        #Hvis vi får nul data, så returnerer vi
        if history.empty: 
            return insights

        #Vi får vores tickers
        tickers = history.index.levels[0]

        returns = {}

        #Looper over vores tickers, hvis nogle af dem har tomme data eller close ikke er der, så dropper vi dem
        for ticker in tickers:
            ticker_history = history.loc[ticker]
            symbol = SymbolCache.GetSymbol(ticker)
            if ticker_history.empty or "close" not in ticker_history or ticker_history.close.isnull().values.any() == True or algorithm.Securities[symbol].HasData == False or algorithm.Securities[symbol].Price == 0:
                history.drop(ticker, level=0)
                continue

            ticker_history = ticker_history.close
            dailyreturn = ticker_history[-2]-ticker_history[0]

            if math.isnan(dailyreturn) == True:
                continue
            
            returns[symbol] = dailyreturn

        #algorithm.Securities[symbol].IsTradable
        rj = sum(returns.values())/len(returns.keys())

        weights = {}
        sum123 = 0
        for key, value in returns.items():
            sum123 += abs(value-rj)

        for key, value in returns.items():
            weight = -(value-rj)/sum123
            weights[key] = weight
        
        for key,value in weights.items():
            if value > 0:
                direction = InsightDirection.Up
            else:
                direction = InsightDirection.Down
            insights.append(Insight.Price(key, Expiry.EndOfDay(time+timedelta(days=1)), direction, weight = value))

        return insights


    def OnSecuritiesChanged(self, algorithm, changes):
        for added in changes.AddedSecurities:
            self.symbolData.append(added.Symbol)

        for removed in changes.RemovedSecurities:
            self.symbolData.remove(removed.Symbol)

# Your New Python File
#region imports
from AlgorithmImports import *
from QuantConnect import Resolution, Extensions
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Algorithm.Framework.Portfolio import *
from itertools import groupby
from datetime import datetime, timedelta
from pytz import utc
UTCMIN = datetime.min.replace(tzinfo=utc)
#endregion
class WeightedPortfolio(PortfolioConstructionModel):


    def __init__(self):
        self.insightCollection = InsightCollection()
        self.removedSymbols = []
        
        self.nextRebalance = None


    def CreateTargets(self, algorithm, insights):

        targets = []

          
        if len(insights) == 0:
            return targets

        # here we get the new insights and add them to our insight collection
        for insight in insights:
            self.insightCollection.Add(insight)
            
        # create flatten target for each security that was removed from the universe
        if len(self.removedSymbols) > 0:
            universeDeselectionTargets = [ PortfolioTarget(symbol, 0) for symbol in self.removedSymbols ]
            targets.extend(universeDeselectionTargets)
            algorithm.Log('(Portfolio module) liquidating: ' + str([x.Value for x in self.removedSymbols]) + ' if they are active, due to not being in the universe')
            self.removedSymbols = []

        expiredInsights = self.insightCollection.RemoveExpiredInsights(algorithm.UtcTime)

        expiredTargetsLog = []
        expiredTargets = []
        for symbol, f in groupby(expiredInsights, lambda x: x.Symbol):
            if not self.insightCollection.HasActiveInsights(symbol, algorithm.UtcTime):
                expiredTargets.append(PortfolioTarget(symbol, 0))
                expiredTargetsLog.append(symbol)
                continue
        
        algorithm.Log(f'(Portfolio module) sold {expiredTargetsLog} due to insight being expired')
        targets.extend(expiredTargets)

        # get insight that have not expired of each symbol that is still in the universe
        activeInsights = self.insightCollection.GetActiveInsights(algorithm.UtcTime)

        # get the last generated active insight for each symbol
        lastActiveInsights = []
        for symbol, g in groupby(activeInsights, lambda x: x.Symbol):
            lastActiveInsights.append(sorted(g, key = lambda x: x.GeneratedTimeUtc)[-1])
        
        # determine target percent for the given insights
        boughtTargetsLog = []
        for insight in lastActiveInsights:
            allocationPercent = insight.Weight * abs(insight.Direction)
            target = PortfolioTarget.Percent(algorithm, insight.Symbol, allocationPercent)
            boughtTargetsLog.append(insight.Symbol)
            targets.append(target)
        
        algorithm.Log(f'(Portfolio module) Bought {boughtTargetsLog} stocks, that expires at {Expiry.EndOfMonth}')

        return targets

        
    def OnSecuritiesChanged(self, algorithm, changes):
        
        
        newRemovedSymbols = [x.Symbol for x in changes.RemovedSecurities if x.Symbol not in self.removedSymbols]
        
        # get removed symbol and invalidate them in the insight collection
        self.removedSymbols.extend(newRemovedSymbols)
        self.insightCollection.Clear(self.removedSymbols)
            
        removedList = [x.Value for x in self.removedSymbols]
        algorithm.Log('(Portfolio module) securities removed from Universe: ' + str(removedList))
# region imports
from AlgorithmImports import *
from MeanReversionAlpha import MeanReversion
from WeightedPortfolioConstructionModel import WeightedPortfolio
# endregion

class EmotionalYellowGull(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2016, 1, 1)  # Set Start Date'
        self.SetEndDate(2021, 12, 20)
        self.SetCash(500000)  # Set Strategy Cash
        self.UniverseSettings.Resolution = Resolution.Minute
        self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)

        seeder = FuncSecuritySeeder(self.GetLastKnownPrices)
        self.SetSecurityInitializer(lambda security: seeder.SeedSecurity(security))

        self.SetBenchmark('SPY')

        etf_symbol = "XLF"

        universe = self.Universe.ETF(etf_symbol, Market.USA, 
                   self.UniverseSettings, self.ETFConstituentsFilter)
        self.AddUniverse(universe)

        self.AddAlpha(MeanReversion())
        self.SetPortfolioConstruction(WeightedPortfolio())
        self.SetExecution(ImmediateExecutionModel())

        self.lastMonth = -1

        self.num_coarse = 20

    def ETFConstituentsFilter(self, constituents: List[ETFConstituentData]) -> List[Symbol]:
        if self.Time.month == self.lastMonth:
	        return Universe.Unchanged
        self.lastMonth = self.Time.month

        selected = sorted([c for c in constituents if c.Weight],
            key=lambda c: c.Weight, reverse=True)[:self.num_coarse]
        return [c.Symbol for c in selected]