Overall Statistics
Total Trades
22054
Average Win
0.22%
Average Loss
-0.23%
Compounding Annual Return
34.316%
Drawdown
3.800%
Expectancy
0.062
Net Profit
342.613%
Sharpe Ratio
6.747
Probabilistic Sharpe Ratio
100%
Loss Rate
45%
Win Rate
55%
Profit-Loss Ratio
0.94
Alpha
0.246
Beta
-0.025
Annual Standard Deviation
0.036
Annual Variance
0.001
Information Ratio
1.114
Tracking Error
0.129
Treynor Ratio
-9.774
Total Fees
$389219.56
from Execution.ImmediateExecutionModel import ImmediateExecutionModel
from collections import deque
import numpy as np


ll = 3
ul= 3

EmergingMarkets = [
    ("EFO","EFU",-1,3,3), #Proshares MSCI EAFE
    ("UPV","EPV",-1,3,3), #Proshares MSCI Developed EU
    ("FXP","XPP",-1,3,3), #Proshares MSCI China
    ("EWV","EZJ",-1,3,3)] #Proshares MSCI Japan]
    

NotLiquid = [
    ("SAA", "SDD"),
    ("MZZ", "MVV", -1,3,3),
    ("UMDD", "SMDD", -1,3,3),
     ("GLL","UGL",-1,3,3),#Proshares Bloomberg Gold Subindex
      ("AGQ","ZSL",-1,3,3),#Proshares Bloomberg Silver Subindex 
         ("YCS","YCL",-1,3,3),
         ("DSLV","USLV",-1,3,3), 
    ("UGLD","DGLD",-1,3,3),
    ("GUSH","DRIP",-1,3,3), #Direxion Oils and Gas Exploration
    ("RUSL","RUSS",-1,3,3), #Direxion Russia
    ("GASL","GASX",-1,3,3), #Direxion Natural Gas
    ("FAZ","FAS",-1,3,3),#Direxion Financials
     ("ERY","ERX",-1,3,3), #Direxion Energy
      ("YINN","YANG",-1,3,3)
    ] + EmergingMarkets

USTreasury = [
  ("TBT","UBT",-1,3,3), #Proshares ICE U.S. Treasury 20+ Year Bond
  ("PST","UST",-1,3,3), #Proshares ICE U.S. Treasury 7 Year Bond
  ("TMF","TMV",-1,3,3)]
  
LiquidETFCompetition = [
    ("UGAZ","DGAZ",-1,3,3),
("ERY","ERX",-1,3,3),  
("NUGT","DUST",-1,3,3),
("UCO","SCO",-1,3,3),
("NUGT","DUST",-1,3,3),
("TECS","TECL",-1,3,3),
("SOXS","SOXL",-1,3,3)]

SP500 = [  #Proshares SP Small Cap
     #Proshares SP Mid Cap 2x 
     #Proshares SP Mid Cap 3x
    ("SPY", "SH", -1, 3,3), #-1
    ("SDS","SSO",-1,3,3),#Proshares SP500 2x
    ("UPRO","SPXU",-1,3,3), #3x
    ("SPXL","SPXS",-1,3,3)]# 3x

NASDAQ = [ 
    ("TQQQ","SQQQ",-1,ll,ul), #Proshares Nasdaq 3x
    ("QQQ","PSQ",-1,ll,ul ), #1x
    ("QLD","QID",-1,ll,ul)] #2x
    
DJIA  = [
    ("DIA", 'DOG', -1, 3,3), #Proshares Dow 1x
    ("SDOW","UDOW",-1,3,3),#Proshares Dow 3x
    ("DDM","DXD",-1,3,3)]  #Proshares Dow 2x    


Russell2000 = [
    ("URTY","SRTY",-1,3,3), #Proshares Russel 3x
    ("RWM","IWM",-1,3,3), #Proshares Russel 1x
    ("UWM","TWM",-1,3,3)]
    
DirexionETFs = [ 
  ("TECL","TECS",-1,3,3),#Direxion Tech 3x
  ("TNA","TZA",-1,3,3), #Direxion Small Cap 3x
  
  ("LABU","LABD",-1,3,3), #Direxion Biotech
  
  
  
  ("NUGT","DUST",-1,3,3), #Direxion Gold Miners
  ("JNUG","JDST",-1,3,3), #Direxion Junior Gold Miners
 
 ] 
  
ProsharesSectorETF =  [  
    ("UYM","SMN",-1,3,3), #Proshares Dow Jones U.S. Basic Materials    
    ("UBIO","ZBIO",-1,3,3), #Proshares Nasdaq Biotech  3x
    ("BIB","BIS",-1,3,3), #Proshares Nasdaq Biotech  2x
    ("SCOM","UCOM",-1,3,3), #Proshares S&P Communication Services Select Sector  3x
    ("SKF","UYG",-1,3,3), #Proshares Dow Jones U.S. Financials
    ("FINU","FINZ",-1,3,3), #Proshares S&P Financial Select Sector
    ("RXD","RXL",-1,3,3), #Proshares Dow Jones U.S. Health Care
    ("UXI","SIJ",-1,3,3), #Proshares Dow Jones U.S. Industrials
    ("DIG","DUG",-1,3,3), #Proshares Dow Jones U.S. Oil & Gas
    ("SRS","URE",-1,3,3), #Proshares Dow Jones Real Estate
    ("USD","SSG",-1,3,3), #Proshares Dow Jones U.S. Semiconductors
    ("ROM","REW",-1,3,3), #Proshares Dow Jones U.S. Technology
    ("SDP","UPW",-1,3,3)]     
    
Commoditities = [
     ("OILU","OILD",-1,2,3), #Proshares Bloomberg WTI Crude Oil Subindex 3x
    ("UCO","SCO",-1,3,3),#Proshares Bloomberg WTI Crude Oil Subindex 2x
    ("ERY","ERX",-1,3,3)]  
    
    
AllPairs = Commoditities + ProsharesSectorETF+ DirexionETFs + Russell2000 + EmergingMarkets + DJIA + NASDAQ + SP500 + LiquidETFCompetition 

    
def fetch_symbols(Pairs):
    symbols = []
    for info in Pairs:
        symbols.append(info[0])
        symbols.append(info[1])
    return symbols



Log = False
Pairs = DirexionETFs


RiskCap= -.0020
LossCap = 3

class LETFArb(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2015, 1, 1)  # Set Start Date
        self.SetEndDate(2020, 1, 14)
          
        self.SetBrokerageModel(BrokerageName.AlphaStreams)
        self.BettingSize =  float(1/len(fetch_symbols(Pairs)))
        self.SetCash(round(50000/self.BettingSize))
        self.Lookback = 6000
        self.losscap = LossCap
        self.riskcap = RiskCap
        self.PairData= {}
        
        
        for info in Pairs:
            self.AddEquity(info[0], Resolution.Minute)
            self.AddEquity(info[1], Resolution.Minute)
            
        
        self.SetExecution(ImmediateExecutionModel())
        self.SetBenchmark("SPY")
        
        symbols = []
        
        for symbol in fetch_symbols(Pairs):
            symbols.append(Symbol.Create(symbol, SecurityType.Equity, Market.USA))
        
        
        self.SetUniverseSelection(ManualUniverseSelectionModel(symbols))
        
        for info in Pairs:
            index_h= self.History(self.Symbol(info[0]), self.Lookback)
            letf_h = self.History(self.Symbol(info[1]), self.Lookback)
            
            if ("close" in index_h.columns) and ("close" in letf_h.columns):
                index_prices = index_h["close"]
                letf_prices = letf_h["close"]
                
                letf = letf_prices.pct_change().dropna()
                index = index_prices.pct_change().dropna()
                
                spreads = np.log(1+letf) - np.log(1+info[2]*index)
                
                
                index_prices =[index_prices.iloc[-2], index_prices.iloc[-1]]
                letf_prices =[letf_prices.iloc[-2], letf_prices.iloc[-1]]
                
                self.PairData[info] = {
                    "Spreads":deque(spreads, maxlen= self.Lookback),
                    "IndexPrices": deque(index_prices, maxlen =2),
                    "LETFPrices": deque(letf_prices, maxlen=2),
                    "Loss": 0,
                   
                }
            else:
                self.PairData[info] = {
                    "Spreads":deque([0], maxlen= self.Lookback),
                    "IndexPrices": deque([0], maxlen =2),
                    "LETFPrices": deque([0], maxlen=2),
                    "Loss":0,
                    
                }
           
        self.SetTimeZone("America/New_York")
        self.SetWarmUp(timedelta(1))
    
    def OnData(self, data):
        
        for pairsinfo in self.PairData:
            IndexTicker = pairsinfo[0]
            LETFTicker = pairsinfo[1]
            
            if (data.Bars.ContainsKey(IndexTicker) and (data.Bars.ContainsKey(LETFTicker))):           
                
                IndexPrices = self.PairData[pairsinfo]["IndexPrices"]
                IndexPrices.append(float(data.Bars[IndexTicker].Close))
                
                LETFPrices = self.PairData[pairsinfo]["LETFPrices"]
                LETFPrices.append(float(data.Bars[LETFTicker].Close))
                
                self.PairData[pairsinfo]["IndexPrices"] = IndexPrices
                self.PairData[pairsinfo]["LETFPrices"] = LETFPrices
                 
            
                if len(IndexPrices) ==2:
                    
                    
                    if IndexPrices[-2] == 0:
                        continue
                    
                    IndexReturn = float(
                        (IndexPrices[-1] - IndexPrices[-2]) / 
                        IndexPrices[-2]
                        )
                        
                        
                    if LETFPrices[-2] == 0:
                        continue
                    
                    LETFReturn = float(
                        (LETFPrices[-1] - LETFPrices[-2]) / LETFPrices[-2]
                        )
                        
                    Leverage = pairsinfo[2]    
                    ExpectedReturn = np.log(1+Leverage*IndexReturn)
                    LETFReturn = np.log(1+ LETFReturn)
                    Spread = float(LETFReturn - ExpectedReturn)        
                    
                    Spreads = self.PairData[pairsinfo]["Spreads"]
                    if Spread !=0:
                        Spreads.append(Spread)
                    self.PairData[pairsinfo]["Spreads"] =Spreads
                    
                    if len(Spreads) >= self.Lookback:
                        
                         
                        LowerLimit = pairsinfo[3]
                        UpperLimit = pairsinfo[4]
                        
                        SpreadDeviations = np.std(Spreads)
                
                        DiscountBand = float(-1* LowerLimit*SpreadDeviations)
                        PremiumBand = float(UpperLimit * SpreadDeviations)
                
                        Discount = Spread <= DiscountBand
                        Premium = Spread >= PremiumBand
                        
                        OpenPosition = (self.Securities[LETFTicker].Invested) and (self.Securities[IndexTicker].Invested)
                        msg1 = IndexTicker +" " +str(Spread)
                        msg2 = LETFTicker + " "+str(Spread)
                
                        if (Discount and not OpenPosition):
                    
                    
                            self.EmitInsights(Insight.Price(LETFTicker, timedelta(60), InsightDirection.Up))
                            self.EmitInsights(Insight.Price(IndexTicker, timedelta(60), InsightDirection.Down))
                            
                            self.SetHoldings([PortfolioTarget(LETFTicker, self.BettingSize), PortfolioTarget(IndexTicker, self.BettingSize)])
                           
                            self.Log(msg1)
                            self.Log(msg2)
                    
                   
                        elif(Premium and OpenPosition):
                           
                            pl = (self.Portfolio[IndexTicker].UnrealizedProfit + self.Portfolio[LETFTicker].UnrealizedProfit)/self.Portfolio.TotalPortfolioValue
                            if pl>0:
                                self.EmitInsights(Insight.Price(LETFTicker, timedelta(300), InsightDirection.Flat))
                                self.EmitInsights(Insight.Price(IndexTicker, timedelta(300), InsightDirection.Flat))
                                self.Liquidate(LETFTicker)
                                self.Liquidate(IndexTicker)
                                self.PairData[pairsinfo]["Loss"] = 0
                                if Log: 
                                    self.Log(msg1)
                                    self.Log(msg2)
                            else:
                                self.PairData[pairsinfo]["Loss"] += 1
                                if (self.PairData[pairsinfo]["Loss"] >=self.losscap) or pl < self.riskcap:
                                    self.EmitInsights(Insight.Price(LETFTicker, timedelta(300), InsightDirection.Flat))
                                    self.EmitInsights(Insight.Price(IndexTicker, timedelta(300), InsightDirection.Flat))
                                    self.Liquidate(LETFTicker)
                                    self.Liquidate(IndexTicker)
                                    self.PairData[pairsinfo]["Loss"] = 0
                                    if Log:
                                        self.Log(msg1)
                                        self.Log(msg2)
                            
                        elif(OpenPosition) and not(Premium or Discount):
                            pl = (self.Portfolio[IndexTicker].UnrealizedProfit + self.Portfolio[LETFTicker].UnrealizedProfit)/self.Portfolio.TotalPortfolioValue
                            if pl >0 and self.PairData[pairsinfo]["Loss"] > 0:
                                self.EmitInsights(Insight.Price(LETFTicker, timedelta(60), InsightDirection.Flat))
                                self.EmitInsights(Insight.Price(IndexTicker, timedelta(60), InsightDirection.Flat))
                                self.Liquidate(LETFTicker)
                                self.Liquidate(IndexTicker)
                                self.PairData[pairsinfo]["Loss"] = 0
                                if Log: 
                                    self.Log(msg1)
                                    self.Log(msg2)
                            
        else:
            pass