Overall Statistics
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel

# Your New Python File
from clr import AddReference                                        
AddReference("System")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Common")

#intro de coarsefine:
AddReference("System.Core")
AddReference("System.Collections")

#intro de indicadores, warmup:
AddReference("QuantConnect.Indicators")

#intro de livefeatures:
from clr import AddReference
AddReference("System.Core")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Common")


#De generico:
from System import *
from QuantConnect import *
from QuantConnect.Orders import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Selection import *
from Alphas.HistoricalReturnsAlphaModel import HistoricalReturnsAlphaModel
from QuantConnect.Algorithm.Framework.Execution import *
from QuantConnect.Algorithm.Framework.Risk import *
from QuantConnect.Algorithm.Framework.Alphas import AlphaModel, Insight, InsightType, InsightDirection            ###NEW##, Magnitude 
 
 #De coarsefine:
from System.Collections.Generic import List
from QuantConnect.Data.UniverseSelection import *       
from QuantConnect.Algorithm import QCAlgorithm #debe de ser el mismo que Algorithm import*
 
 #from LITTER-MAN:
from Portfolio.BlackLittermanOptimizationPortfolioConstructionModel import *
from Portfolio.UnconstrainedMeanVariancePortfolioOptimizer import UnconstrainedMeanVariancePortfolioOptimizer

 
 #from meanvariance:
 
from QuantConnect.Algorithm.Framework.Alphas import *
from Portfolio.MeanVarianceOptimizationPortfolioConstructionModel import *
 
 #de indicadores, warmup:
from QuantConnect.Indicators import *
from QuantConnect.Data import *
from datetime import datetime
 
#de livefeatures:
from QuantConnect.Data.Market import *
from QuantConnect.Python import PythonData

import numpy as np
from datetime import datetime
from datetime import timedelta
import json
  
#from indicatorwarmup:
from QuantConnect.Securities import *

#del contruction alpha:
from Alphas.MacdAlphaModel import MacdAlphaModel
from Alphas.PearsonCorrelationPairsTradingAlphaModel import PearsonCorrelationPairsTradingAlphaModel
from Portfolio.BlackLittermanOptimizationPortfolioConstructionModel import BlackLittermanOptimizationPortfolioConstructionModel

from QuantConnect.Algorithm.Framework.Risk import RiskManagementModel
from Execution.ImmediateExecutionModel import ImmediateExecutionModel
 
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel


class LiveAlpha0(QCAlgorithm):

    def Initialize(self):
        
        self.SetBrokerageModel(BrokerageName.AlphaStreams)
        self.SetCash(250000)  
        self.UniverseSettings.Resolution = Resolution.Daily
        self.UniverseSettings.Leverage = 1
        self.UniverseSettings.FillForward = False
        self.UniverseSettings.ExtendedMarketHours = False       #new cuando INFLUYE?
        self.SetStartDate(2020,2,14) #SUBPRIME self.SetStartDate(2018,10,1)  #COVID self.SetStartDate(2020,3,21-23) # Litter solo jala 6 m del (2020,11,1) al delta(5) o mejor 7 dias antes Set Start Date LITTER tiene pedos con alargar fecha >2020 y en tiempo real, que falta?                                      # self.SetEndDate(datetime.now() - timedelta (1)) #Trying to dynamically access a method that does not exist throws a TypeError exception. To prevent the exception, ensure each parameter type matches those required by the 'float'>) method. Please checkout the API documentation.at Updateself.roc.Update(utcTime in BlackLittermanOptimizationPortfolioConstructionModel.py:299TypeError : No method matches given arguments for Update: (<class 'datetime.datetime'>, <class 'float'>)     (Open Stacktrace)
        self.SetEndDate(2020,4,8)  # SUBPRIME? self.SetEndDate(2018,12,31)  #COVID self.SetEndDate(2020,3,27)   # le faltara el update p que actualice fechas mas de 6 meses?
        self.numberOfSymbolsCoarse = 888        # Hasta 9999, no trate mas, se podra?
        self.numberOfSymbolsFine = 5            #hasta 555
        self.dollarVolumeBySymbol= { }
        self._changes = None
        self.month = None
        self.universe = { }
        self.SetWarmUp(200) # Warm up 200 bars for all subscribed data.
        self.SetWarmUp(timedelta(1800)) # Warm up 7 o 1800? days of data.
        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)
        self.spy = self.AddEquity("SPY", Resolution.Daily).Symbol
        self.amat = self.AddEquity("AMAT", Resolution.Daily).Symbol
        self.intc = self.AddEquity("INTC", Resolution.Daily).Symbol
        self.SetBenchmark("SPY")
        
####    
        #self.AddAlpha(ConstantAlphaModel()) #0.8??, HOUR= 2?? # CON timedelta(1)))  #SI INFLUYE aunque menos positivo
        
        
        #self.SetAlpha(ConstantAlphaModel(InsightType.Price, InsightDirection.Up, timedelta(minutes = 20), 0.025, 0.25)) # CON timedelta(1)))  #SI INFLUYE aunque menos positivo
        self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel()) 

        #self.AddAlpha(MacdAlphaModel(12, 26, 9, MovingAverageType.Simple, Resolution.Daily))
        #self.SetPortfolioConstruction(BlackLittermanOptimizationPortfolioConstructionModel(alta saber poner args, methods interconectar))
        #self.SetPortfolioConstruction(MySectorWeightingPortfolioConstructionModel(falta saber poner args, methods))
        
        #self.SetUniverseSelection(TechnologyUniverseModule())              #how connecting modules?
            
                         # define a 10-period daily RSI indicator with shortcut helper method
        #self.rsi = self.RSI("SPY", 10,  MovingAverageType.Simple, Resolution.Daily)
                   
###      
                             #1. Save a RollingWindow with type TradeBar and length of 5 as self.window
        self.window = RollingWindow[TradeBar](5)            #NO INFLUYE
        
        self.SetAlpha(MyAlpha())
        self.SetPortfolioConstruction(BlackLittermanOptimizationPortfolioConstructionModel())
        
                            # self.SetRiskManagement(MaximumSectorExposureRiskManagementModel(0.33))  
        self.SetRiskManagement(MaximumDrawdownPercentPortfolio()) #0.33? difference between .Set... and .Add..?
        self.AddRiskManagement(MaximumDrawdownPercentPortfolio()) 
                
        self.SetExecution(ImmediateExecutionModel())    
      
        
##
        self.long = []
        self.short = []
     
        
        
    def CoarseSelectionFunction(self, coarse):
      
            
                                                                                    #short long no lleva volume
        sortedByDollarVolume = sorted([x for x in coarse if x.HasFundamentalData and x.Volume > 100000 and (float(x.Price) > 5) and x.DollarVolume >1e7],  # and x.Price < 500
            key = lambda x: x.DollarVolume, reverse = True) [:self.numberOfSymbolsCoarse]
            
                                     # return [ x.Symbol for x in sortedByDollarVolume[:self.__numberOfSymbols] ]    # return the symbol objects of the top entries from our sorted collection
        self.dollarVolumeBySymbol = {x.Symbol:x.DollarVolume for x in sortedByDollarVolume}
        
                                     #if no security has meet the QC500 criteria, the Universe is Unchanged:
        if len(self.dollarVolumeBySymbol) == 0:
            self.Debug("Universe.Unchanged!!")
            return Universe.Unchanged
            
        return list(self.dollarVolumeBySymbol.keys())
        
    
    def FineSelectionFunction(self, fine):
                                    # drop stocks which don't have the information we need.
                                   
                
        sortedByPau = sorted([x for x in fine if x.FinancialStatements.IncomeStatement.NormalizedIncomeAsReported.Value >= 0.001
                                                   and x.FinancialStatements.IncomeStatement.TotalRevenue.Value >= 0.03
                                                   and x.ValuationRatios.PERatio >= 10         # Amazon = 50 S&P:13-15 P/E of 25, above the S&P average, trades at 25 times earnings
                                                   and x.MarketCap > 1e5
                                            
                                                   and x.OperationRatios.AVG5YrsROIC.Value != 0          # 10% 
                                                   and x.OperationRatios.ROA5YrAvg.Value != 0            # > 0.02, 5% es amazon y yo tenia 0.11 si .2 es 20%, .002 es 
                                                   and x.OperationRatios.ROE5YrAvg.Value != 0                  # > 0.02
                                                   and x.OperationRatios.ProfitMargin5YrAvg.Value != 0         # > 0.02
                                                   and x.OperationRatios.GrossMargin5YrAvg.Value  != 0            # > 0.02
                                                   and x.OperationRatios.GrossProfitAnnual5YrGrowth.Value != 0   # > 0.02
                                                   
                                                   
                                                   and x.OperationRatios.ROIC.OneYear >= 0.001                 # Net Income / (Total Equity + Long-term Debt and Capital Lease Obligation + Short-term Debt and Capital Lease Obligation)
                                                   and x.OperationRatios.ROE.OneYear >= 0.001               # Net Income / Average Total Common Equity
                                                   and x.OperationRatios.ROA.OneYear >= 0.001                    # >= 0.01 Net Income / Average Total Assets
                                                   and x.OperationRatios.GrossMargin.OneYear >= 0.001 
                                                   
                                                   and x.OperationRatios.ROIC.SixMonths >= 0.001  
                                                   and x.OperationRatios.ROIC.ThreeMonths >= 0.03  
                                                   and x.OperationRatios.ROIC.Value >= 0.03 
                                                   
                                                   and x.OperationRatios.OperationMargin.Value >= 0.05
                                                   and x.OperationRatios.TotalAssetsGrowth.Value > 0.03
                                                   and x.OperationRatios.OperationRevenueGrowth3MonthAvg.GetPeriodValues().Values != 0  # 15%  ///SI con:GetPeriodValues() != 0, .Value != 0, > 0.1, .HasValues(), ///NO: 
                                                 
                                                   
                                                   and x.FinancialStatements.CashFlowStatement.EarningsLossesFromEquityInvestments.Value != 0
                                                   and x.OperationRatios.DebttoAssets.Value >= 0.08
                                                   and x.OperationRatios.OperationMargin.Value >= 0.08
                                                   and x.OperationRatios.TotalAssetsGrowth.Value > 0.06
                                                   
                                                   and x.OperationRatios.FCFNetIncomeRatio.Value >=0.02 #new >=0.1 #ya con estos ya me salia algo pesimista: #AQUI HOY, revisar mañana notas y ver que sigue! EXCELENTE SUPER WOMAN!! ;)
                                                   and x.OperationRatios.FCFtoCFO.Value >=0.2
                                                   
                                                   
                                                   #and x.OperationRatios.RegressionGrowthOperatingRevenue5Years.Value != 0
                                                  # and x.OperationRatios.ROE.SixMonths != 0  
                                                  # and x.OperationRatios.ROE.ThreeMonths != 0 
                                                  # and x.OperationRatios.ROE.Value >= 0.001 
                                                 
                                                 #  and x.OperationRatios.CurrentRatioGrowth.Value != 0
                                                  # and x.OperationRatios.NetIncomeGrowth.Value != 0
                                                   
                                                  #git:
                                                
                                                 #  and x.OperationRatios.ROA.Value>= 0.01
                                                 #  and x.ValuationRatios.PriceChange1M > 0.1
                                                 #  and x.ValuationRatios.SalesPerShare * x.EarningReports.DilutedAverageShares.Value > 10000000
                                                 #  and x.ValuationRatios.PERatio > 0.1
                                                 #  and x.ValuationRatios.PBRatio > 0.1
                                                 #  and x.ValuationRatios.BookValuePerShare>0.1
                                                 #  and x.EarningReports.BasicAverageShares.Value >= 0.1
                                                 #  and x.EarningReports.BasicAverageShares.ThreeMonths > 0.1
                                                 #  and x.EarningReports.BasicEPS.TwelveMonths > 0.1
                                                 #  and x.EarningReports.BasicAverageShares.ThreeMonths * x.EarningReports.BasicEPS.TwelveMonths * x.ValuationRatios.PERatio > 1
                                                 #  and x.EarningRatios.EquityPerShareGrowth.OneYear > 0.25 #0.25m? que es m?
                                                 #  and x.FinancialStatements.BalanceSheet.TotalEquity
                                                 # and (algorithm.Time - x.SecurityReference.IPODate).days > 180
                                                 # and x.CompanyReference.PrimaryExchangeID == ["NAS", "NYS"] # == / in  
                                                 # and x.CompanyReference.CountryId == "USA"
                                                 # and x.CompanyReference.IndustryTemplateCode == "N"
                                                 
                                                 #test short long
                                                 #and x.ValuationRatios.PriceChange1M > 0.1
                                                 #  and x.ValuationRatios.BookValuePerShare]
                                                                ],
                        key = lambda x: self.dollarVolumeBySymbol[x.Symbol], reverse = True)               
                        
        self.Debug('remained to select %d'%(len(sortedByPau)))
                        
        if len(sortedByPau) == 0:
            self.Debug("aqui ya no jalo, por? muchos parametros o?")
            return Universe.Unchanged
###     
        self.sortedByPau = [ ]
        
        stock_dict = {}
                         # assign a index? to each stock, you can also change the rule of scoring here.
        #for i,ele in enumerate(sortedByPau):
         #   stock1 = sortedByPau[0]
          #  stock2 = sortedByPau[1]
           # stock3 = sortedByPau[2]
        #    stock4 = sortedByPau[3]
         #   stock5 = sortedByPau[4]
         

                # sotre the top stocks into the long_list and the bottom ones into the short_list
        self.long = [x.Symbol for x in sortedByPau[:self.numberOfSymbolsFine]]    
        self.short = [x.Symbol for x in sortedByPau[-self.numberOfSymbolsFine:]]
    
        return self.long + self.short
       
       # return [x.Symbol for x in sortedByPau[:self.numberOfSymbolsFine]]                 
                
###
    def OnData(self, data):
        securities = data.Keys
        n_securities = len(securities)
                                                # check if this algorithm is still warming up
                                        #  if self.rsi.IsReady:
                                                    # get the current RSI value
                                        #     rsi_value = self.rsi.Current.Value
                                                    # get the current average gain of rsi
                                             #    average_gain = self.rsi.AverageGain.Current.Value
                                                    # get the current average loss of rsi
                                        #   average_loss = self.rsi.AverageLoss.Current.Value
        if self._changes is None: return
        if self.month == self.Time.month: return        #self.Debug("si return means weve already rebalanced that self.month")
        self.month = self.Time.month
        

###NEW                                # for s in securities:
                                     # Manually update the Indicators
        for symbol in self.universe.keys():
            if data.Bars.ContainsKey(symbol):
                self.universe[symbol].update(data[symbol].EndTime, data[symbol].Close)
                
##                               # If our window is not full use return to wait for tomorrow
        if not self.window.IsReady:
            self.Debug("no ready")
            return
                        # change overnight price    # si abrimos en positivos y cerro antes en negativos (-5 -(-2.5) = -2.5 ASUMOO q subira
        delta = self.window[0].Open - self.window[1].Close 
        
#####   
        
        for security in self._changes.AddedSecurities:
                            # antes del brokerage.alpha : if security.Fundamentals.EarningRatios.EquityPerShareGrowth.OneYear > 0.25):
                            # o if self._changes is not None: 
            if delta < -25.5:       #NEW          
                self.SetHoldings(security.Symbol, 1/n_securities)
              # self.SetHoldings(s, 1/n_securities)
              
        for security in self._changes.RemovedSecurities:
            if security.Invested or self.Portfolio.TotalUnrealizedProfit < -1000: 
                self.Liquidate(security.Symbol)      

    def OnSecuritiesChanged(self, changes):
        self._changes = changes
        self.Debug("{}: {}".format(self.Time, changes))
        
    def Update():
        pass

class MaximumDrawdownPercentPortfolio(RiskManagementModel):
                      
                         # Initializes a new instance of the MaximumDrawdownPercentPerSecurity class.   Args:  maximumDrawdownPercent: The maximum percentage drawdown allowed for any single security holding
    def __init__(self, MaximumDrawdownPercentPortfolio = 0.15): #0.15 (este fue mas alto .15 ) ahora 0.33 ahora 0.85 muy bajo lo dejo en 0.15
                      
        self.maximumDrawdownPercent = -abs(MaximumDrawdownPercentPortfolio)
                        
                        # Manages the algorithm's risk at each time step. #Args: algorithm: The algorithm instance. 
    def ManageRisk(self, LiveAlpha0, targets):
                
                         #targets: The current portfolio targets to be assessed for risk
        targets = []
        for stocks in LiveAlpha0.Securities: #for self.longShortPau instead of stocks?
            security = stocks.Value     

           # if not security.Invested:
            #    continue

            pnl = security.Holdings.UnrealizedProfitPercent
                        
            if pnl < self.maximumDrawdownPercent:
                # liquidate
                #si llega aqui xq bota los 2 deug  self.Debug("?????")
                targets.append(PortfolioTarget(security.Symbol, 0))
                

        return targets
        
        
    

class MyAlpha(AlphaModel):
    symbols = []
    
    def Update(self, algorithm, data):
        insights = []
        for symbol in self.symbols:
            if not (data.ContainsKey(symbol) and data[symbol] is not None):
                continue
            
            # The BlackLittermanOptimizationPortfolioConstructionModel uses the insight magnitude to optimize 
            #  the portfolio allocations
            magnitude = round(random(), 4)
            
            insight = Insight.Price(symbol, timedelta(days=1), InsightDirection.Up, magnitude, confidence=1, sourceModel='MyAlpha', weight=0.1)
            insights.append(insight)
        return insights
    
    def OnSecuritiesChanged(self, algorithm, changes):
        for security in changes.AddedSecurities:
            self.symbols.append(security.Symbol)
        
        for security in changes.RemovedSecurities:
            if security.Symbol in self.symbols:
                self.symbols.remove(security.Symbol)
        
#class BlackLittermanOptimizationPortfolioConstructionModel():    pass

###
#self.AddAlpha( RsiAlphaModel() )
#self.AddAlpha( EmaCrossAlphaModel() )
#return Insight.Group( [ insight1, insight2, insight3 ] )

"""
class ConstantAlphaModel(LiveAlpha0):
    
    def __init__(self): #error takes 1 arg and 6 were given?
     self.mom = []
         
    def OnSecuritiesChanged(self, LiveAlpha0, changes):
       # self.mom = []
        self._changes = changes
        for security in changes.AddedSecurities:
            symbol = security.Symbol
            self.mom.append({"symbol":symbol, "indicator":LiveAlpha0.MOM(symbol, 14, Resolution.Daily)})
        
    def Update(self, LiveAlpha0, data):   
                        # Perform analysis, then and emit insights: /We can return a set of Insights together as a group, which signal to the execution model that the insights need to be traded simultaneously.
                        #return Insight.Price("SPY", timedelta(1), InsightDirection.Up)
        
        ordered = sorted(self.mom, key=lambda kv: kv["indicator"].Current.Value, reverse=True)
        return Insight.Group([Insight.Price(ordered[0]['symbol'], timedelta(1), InsightDirection.Up), # IndexError : list index out of range at Update return Insight.Group([Insight.Price(ordered[0]['symbol'] in main.py:line 356
                            Insight.Price(ordered[1]['symbol'], timedelta(1), InsightDirection.Flat) ])
        
        
         


class ConstantAlphaModel(LiveAlpha0):    
    def Update(self, LiveAlpha0, slice): 
                                            #self.spy = self.AddEquity("SPY")
     
      señales = self.long + self.short           # por vacio no activa
     # insights=[]
      señal = Insight.Price("?", timedelta(minutes = 20), InsightDirection.Up, None, None, None, 0.25) #Insight' object is not iterable
      return señal
  #     pass
#    self.AddAlpha(ConstantAlphaModel(InsightType.Price, InsightDirection.Up, timedelta(minutes = 20), 0.025, 0.8)) # CON timedelta(1)))  #SI INFLUYE aunque menos positivo
    def OnSecuritiesChanged(self, LiveAlpha0, changes):
       self._changes = changes
       #self.Debug("{}: {}".format(self.Time, changes))
       pass
"""