Overall Statistics
Total Trades
2
Average Win
0%
Average Loss
-0.26%
Compounding Annual Return
-1.215%
Drawdown
0.300%
Expectancy
-1
Net Profit
-0.260%
Sharpe Ratio
-1.605
Probabilistic Sharpe Ratio
5.501%
Loss Rate
100%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
-0.004
Beta
-0.016
Annual Standard Deviation
0.005
Annual Variance
0
Information Ratio
-1.487
Tracking Error
0.199
Treynor Ratio
0.514
Total Fees
$1.00
Estimated Strategy Capacity
$28000000.00
Lowest Capacity Asset
AAPL 322PLPR8938CM|AAPL R735QTJ8XC9X
Portfolio Turnover
0.00%
#region imports
from AlgorithmImports import *

import numpy as np

# This code implements the pairs trading algorithm detailed in the lecture notes.  Credit to the authors.

class Math585HW(QCAlgorithm):

    
    def Initialize(self):

        self.lookback = 20
        self.k = 2


        self.SetStartDate(2018, 1, 1)  
        self.SetEndDate(2019, 1, 1) 
        self.cash = 1000000
        self.SetCash(self.cash)
        self.SetWarmup(self.lookback + 10)



        self.AddEquity("AMD", Resolution.Daily)
        self.AddEquity("JNJ", Resolution.Daily)
        
        self.amd_history = []
        self.jnj_history = []
        

        #self.bollinger_amd = BollingerBands("AMD", 20, 2, MovingAverageType.Simple, Resolution.Daily)
        #self.bollinger_jnj = BollingerBands("JNJ", 20, 2, MovingAverageType.Simple, Resolution.Daily)


    def OnData(self, data):

        amd_px = self.Securities["AMD"].Price
        jnj_px = self.Securities["JNJ"].Price

        self.amd_history.insert(0, amd_px)
        self.jnj_history.insert(0, jnj_px)

        if len(self.amd_history) > self.lookback:
            self.amd_history.pop()
            self.jnj_history.pop()


        if self.IsWarmingUp:
            return


        amd_mean = np.mean(self.amd_history)
        amd_std = np.std(self.amd_history)
        jnj_mean = np.mean(self.jnj_history)
        jnj_std = np.std(self.jnj_history)


        amd_pos = self.Portfolio['AMD'].HoldingsValue / self.cash
        jnj_pos = self.Portfolio['JNJ'].HoldingsValue / self.cash

        self.Plot("AMD", "Px", amd_px)
        self.Plot(f"AMD", "BB-{self.k}", amd_mean - self.k * amd_std)
        self.Plot("AMD", "BB", amd_mean)
        self.Plot(f"AMD", "BB+{self.k}", amd_mean + self.k * amd_std)
        self.Plot("AMD", "Pos", amd_pos)


        self.Plot("JNJ", "Px", jnj_px)
        self.Plot(f"JNJ", "BB-{self.k}", jnj_mean - self.k * jnj_std)
        self.Plot("JNJ", "BB", jnj_mean)
        self.Plot(f"JNJ", "BB+{self.k}", jnj_mean + self.k * jnj_std)
        self.Plot("JNJ", "Pos", jnj_pos)


        
        if not self.Portfolio["AMD"].IsLong and not self.Portfolio["AMD"].IsShort:
            
            if amd_px > amd_mean + self.k * amd_std:
                self.SetHoldings("AMD", -0.5)
            elif amd_px < amd_mean - self.k * amd_std:
                self.SetHoldings("AMD", 0.5)

        elif self.Portfolio["AMD"].IsLong:
            if amd_px > amd_mean:
                self.SetHoldings("AMD", 0)

        elif self.Portfolio["AMD"].IsShort:
            if amd_px < amd_mean:
                self.SetHoldings("AMD", 0)


        if not self.Portfolio["JNJ"].IsLong and not self.Portfolio["JNJ"].IsShort:
            
            if jnj_px > jnj_mean + self.k * jnj_std:
                self.SetHoldings("JNJ", -0.5)
            elif jnj_px < jnj_mean - self.k * jnj_std:
                self.SetHoldings("JNJ", 0.5)

        elif self.Portfolio["JNJ"].IsLong:
            if jnj_px > jnj_mean:
                self.SetHoldings("JNJ", 0)

        elif self.Portfolio["JNJ"].IsShort:
            if jnj_px < jnj_mean:
                self.SetHoldings("JNJ", 0)
# region imports
from AlgorithmImports import *
# endregion

# Code Re-used from previous homeworks.

class Math585HW(QCAlgorithm):

    def Initialize(self):

        self.ticker = "XOM" #"GS"

        self.SetStartDate(2019, 2, 1)  # Set Start Date
        self.SetEndDate(2021, 2, 1)
        #self.SetCash(1000000)  # Set Strategy Cash
        
        self.AddEquity(self.ticker, Resolution.Daily)

    
        self.POS = 1
        self.init_run = True

    def OnData(self, data: Slice):

        # On first call to OnData, do the following:
        if self.init_run:
            self.init_run = False
            print("Placing Market ORder")
            self.MarketOrder(self.ticker, self.POS)
# region imports
from AlgorithmImports import *
# endregion

# Code Re-used from previous homeworks.

class Math585HW(QCAlgorithm):

    def Initialize(self):

        self.ticker = "XOM" #"GS"

        self.SetStartDate(2019, 2, 1)  # Set Start Date
        self.SetEndDate(2021, 2, 1)
        #self.SetWarmup(100)
        #self.SetCash(1000000)  # Set Strategy Cash

        self.AddEquity(self.ticker, Resolution.Daily)

        #self.SetHoldings(self.ticker, 1)

        self.POS = 1
        self.init_run = True
        self.sold = False

    def OnData(self, data: Slice):

        # On first call to OnData, do the following:
        if self.init_run:
            self.init_run = False
            self.Debug("Placing Market ORder")
            self.MarketOrder(self.ticker, self.POS)
            self.start_px = self.Securities[self.ticker].Price
            self.Debug(f"Starting Price = {self.start_px}")

        else:
            if not self.sold:
        
                px = self.Securities[self.ticker].Price

                if px < self.start_px*0.93 or px > self.start_px*1.07:
                    # Sell:
                    self.MarketOrder(self.ticker, -self.POS)

                    self.sold = True
# region imports
from AlgorithmImports import *
# endregion

# Code Re-used from previous homeworks.

class Math585HW(QCAlgorithm):

    def Initialize(self):

        self.SetStartDate(2019, 2, 1)  # Set Start Date
        self.SetEndDate(2021, 2, 1)
        #self.SetWarmup(100)
        self.SetCash(1000000)  # Set Strategy Cash

        self.AddEquity("GS", Resolution.Daily)
        self.AddEquity("MS", Resolution.Daily)
        self.AddEquity("AMD", Resolution.Daily)
        self.AddEquity("XOM", Resolution.Daily)

        #self.SetHoldings(self.ticker, 1)
        self.init_run = True
        self.sold = False

    def OnData(self, data: Slice):

        # On first call to OnData, do the following:
        if self.init_run:
            self.init_run = False
            self.Debug("Placing Market ORder")

            self.MarketOrder("GS", 500000 / self.Securities["GS"].Price)
            self.MarketOrder("MS", -500000 / self.Securities["MS"].Price)
# region imports
from AlgorithmImports import *
# endregion

# Code Re-used from previous homeworks.

class Math585HW(QCAlgorithm):

    def Initialize(self):

        self.SetStartDate(2019, 2, 1)  # Set Start Date
        self.SetEndDate(2021, 2, 1)
        #self.SetWarmup(100)
        self.SetCash(1000000)  # Set Strategy Cash

        self.AddEquity("GS", Resolution.Daily)
        self.AddEquity("MS", Resolution.Daily)
        self.AddEquity("AMD", Resolution.Daily)
        self.AddEquity("XOM", Resolution.Daily)

        #self.SetHoldings(self.ticker, 1)
        self.init_run = True
        self.sold = False

    def OnData(self, data: Slice):

        # On first call to OnData, do the following:
        if self.init_run:
            self.init_run = False
            self.Debug("Placing Market ORder")

            # Long
            self.MarketOrder("GS", 500000 / self.Securities["GS"].Price)
            self.MarketOrder("AMD", 500000 / self.Securities["AMD"].Price)

            # Short
            self.MarketOrder("MS", -500000 / self.Securities["MS"].Price)
            self.MarketOrder("XOM", -500000 / self.Securities["XOM"].Price)
# region imports
from AlgorithmImports import *
# endregion

# Code Re-used from previous homeworks.
# Referenced "simple_momentum_example.txt" on Sakai.  Approach based on this reference.  Credit to the authors.

class Math585HW(QCAlgorithm):

    def Initialize(self):


        self.SetStartDate(2019, 8, 20)  # Set Start Date
        self.SetEndDate(2020, 7, 20)
        #self.SetWarmup(100)
        self.SetCash(2000000)  # Set Strategy Cash
        self.SetWarmup(20)

        self.AddEquity("AMD", Resolution.Daily)
        self.AddEquity("AMZN", Resolution.Daily)
        self.AddEquity("ROKU", Resolution.Daily)
        self.AddEquity("JPM", Resolution.Daily)

        self.trend_following_security = "AMZN"

        self.sma20 =self.SMA(self.trend_following_security, 20, Resolution.Daily)


    def OnData(self, data: Slice):

        # Don't do anything during warmup period.
        if self.IsWarmingUp:
            return

        # follow the AMZN
        if self.Securities[self.trend_following_security].Price > self.sma20.Current.Value:
            self.SetHoldings(self.trend_following_security, 0.5)

        if self.Securities[self.trend_following_security].Price < self.sma20.Current.Value:
            self.SetHoldings(self.trend_following_security, -0.5)
# region imports
from AlgorithmImports import *
# endregion

# Code Re-used from previous homeworks.
# Referenced "simple_momentum_example.txt" on Sakai.  Approach based on this reference.  Credit to the authors.

class Math585HW(QCAlgorithm):

    def Initialize(self):


        self.SetStartDate(2019, 8, 20)  # Set Start Date
        self.SetEndDate(2020, 7, 20)
        #self.SetWarmup(100)
        self.SetCash(2000000)  # Set Strategy Cash
        self.SetWarmup(20)

        self.AddEquity("AMD", Resolution.Daily)
        self.AddEquity("AMZN", Resolution.Daily)
        self.AddEquity("ROKU", Resolution.Daily)
        self.AddEquity("JPM", Resolution.Daily)

        self.trend_reversal_security = "ROKU"

        self.sma20 =self.SMA(self.trend_reversal_security, 20, Resolution.Daily)


    def OnData(self, data: Slice):

        # Skip execution during warmup
        if self.IsWarmingUp:
            return

        if self.Securities[self.trend_reversal_security].Price > self.sma20.Current.Value:
            self.SetHoldings(self.trend_reversal_security, -0.5)

        if self.Securities[self.trend_reversal_security].Price < self.sma20.Current.Value:
            self.SetHoldings(self.trend_reversal_security, 0.5)
# region imports
from AlgorithmImports import *
# endregion

# Code Re-used from previous homeworks.
# Referenced "simple_momentum_example.txt" on Sakai.  Approach based on this reference.  Credit to the authors.

class Math585HW(QCAlgorithm):

    def Initialize(self):


        self.SetStartDate(2019, 8, 20)  # Set Start Date
        self.SetEndDate(2020, 7, 20)
        #self.SetWarmup(100)
        self.SetCash(2000000)  # Set Strategy Cash
        self.SetWarmup(20)

        self.AddEquity("AMD", Resolution.Daily)
        self.AddEquity("AMZN", Resolution.Daily)
        self.AddEquity("ROKU", Resolution.Daily)
        self.AddEquity("JPM", Resolution.Daily)

        self.trend_following_security = "AMZN"
        self.trend_reversal_security = "ROKU"

        self.follow_sma20 =self.SMA(self.trend_following_security, 20, Resolution.Daily)
        self.reverse_sma20 =self.SMA(self.trend_reversal_security, 20, Resolution.Daily)


    def OnData(self, data: Slice):

        # Do nothign during warmup period
        if self.IsWarmingUp:
            return

        # follow the AMZN
        if self.Securities[self.trend_following_security].Price > self.follow_sma20.Current.Value:
            self.SetHoldings(self.trend_following_security, 0.25)

        if self.Securities[self.trend_following_security].Price < self.follow_sma20.Current.Value:
            self.SetHoldings(self.trend_following_security, -0.25)


        # Go against trend on ROKU
        if self.Securities[self.trend_reversal_security].Price > self.reverse_sma20.Current.Value:
            self.SetHoldings(self.trend_reversal_security, -0.25)

        if self.Securities[self.trend_reversal_security].Price < self.reverse_sma20.Current.Value:
            self.SetHoldings(self.trend_reversal_security, 0.25)
#region imports
from AlgorithmImports import *
#endregion

# This code is modified starting from code on Sakai authored by Ye et. al.  Credit to Prof. Ye for its authorship.  Retrieved from Sakai 2/15/2023

# Result for Jan 1 2018: ['BAC', 'BRK.B', 'JPM']
# Bank of America
# Berkshire Hathaway
# JPMorgan

class Math585HW(QCAlgorithm):

    
    def Initialize(self):
        self.SetStartDate(2018, 1, 1)  
        self.SetEndDate(2018, 1, 2) 

        self.AddUniverse(self.CoarseSelectionFilter, self.FineSelectionFilter)
        self.UniverseSettings.Resolution = Resolution.Daily
        self.SetSecurityInitializer(lambda x: x.SetDataNormalizationMode(DataNormalizationMode.Raw))


    
    def CoarseSelectionFilter(self, coarse):
        
        sortedByDollarVolume = sorted(coarse, key=lambda c: c.DollarVolume, reverse=True)
        filteredByPrice = [c.Symbol for c in sortedByDollarVolume if c.Price>10]
        self.filter_coarse = filteredByPrice[:100]
        return self.filter_coarse
        
    def FineSelectionFilter(self, fine):

        fine1 = [x for x in fine if x.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.FinancialServices]
        
        sortedByMarketCap = sorted(fine1, key=lambda c: c.MarketCap, reverse=True)

        filteredFine = [i.Symbol for i in sortedByMarketCap]

        self.filter_fine = filteredFine[:3]
        
        return self.filter_fine
        

    def OnData(self, data):

        k = [key.Value for key in data.Keys]
        self.Debug(k)







#region imports
from AlgorithmImports import *
#endregion
from AlgorithmImports import *
import numpy as np
import statsmodels.api as model
from statsmodels.tsa.stattools import adfuller

# This code implements the pairs trading algorithm detailed in the lecture notes.  Credit to the authors.
# The method of calculating the ADF is modified from code on slide 162 of lecture 8.  Credit to the authors.


class Math585HW(QCAlgorithm):

    
    def Initialize(self):
        self.SetStartDate(2018, 1, 1)  
        self.SetEndDate(2020, 1, 1) 
        self.SetCash(1000000)
        self.SetWarmup(30)


        self.p = "BAC"
        self.q = "JPM"

        self.AddEquity(self.p, Resolution.Daily)
        self.AddEquity(self.q, Resolution.Daily)

        self.lookback_window = 20 #days

        #self.beta = 0.5624042647804646
        #self.alpha = 2.718503876069648 
        #self.sigma = 0.020898581545820503

        self.Debug("In Init")

    def OnData(self, data):

        if self.IsWarmingUp:
            return

        self.Debug(f"In OnData")

        p_px = self.Securities[self.p].Price
        q_px = self.Securities[self.q].Price

        _, beta, alpha, _, sigma = self.calc_adf(self.History([self.p], self.lookback_window, resolution=Resolution.Daily)["close"].tolist(), self.History([self.q], self.lookback_window, resolution=Resolution.Daily)["close"].tolist())

        self.Debug(f"P price: {p_px}; Q price: {q_px}")

        residual = np.log(p_px) - np.log(q_px) * beta - alpha
        self.Debug(residual)
        z_idx = residual / sigma

        entrythreshold = 2
        exitthreshold = 0

        wtp = 1 / (1 + beta)
        wtq = beta / (1 + beta)
        C = 1000000

        self.Debug(f"Z-idx = {z_idx}")

        #if not self.Portfolio[self.p].Invested:
        if not self.Portfolio[self.p].IsLong and not self.Portfolio[self.p].IsShort:
            if z_idx > entrythreshold:
                self.MarketOrder(self.p, -wtp*C/p_px)
                self.MarketOrder(self.q, wtq*C/q_px)
            elif z_idx < -entrythreshold:
                self.MarketOrder(self.p, wtp*C/p_px)
                self.MarketOrder(self.q, -wtq*C/q_px)

            
        elif self.Portfolio[self.p].IsLong:

            if z_idx >= 0:
                self.Liquidate(self.p)
                self.Liquidate(self.q)


        elif self.Portfolio[self.p].IsShort:
            if z_idx <= 0:
                self.Liquidate(self.p)
                self.Liquidate(self.q)


    def calc_adf(self, close1, close2):
        # This method of calculating the ADF is modified from code on slide 162 of lecture 8.  Credit to the authors.
        logclose1 = np.log(close1)
        logclose2 = np.log(close2)
    
        ind = model.add_constant(logclose1)
        dep = logclose2

        leastsquare = model.OLS(dep, ind)
        prod = leastsquare.fit()

        slope = prod.params[1]
        intercept = prod.params[0]
        residuals = prod.resid
        standard_dev_residuals = np.sqrt(prod.mse_resid)

        # Residuals are mean zero. Therefore the z-index is simply observation over std dev.
        z_index = residuals / standard_dev_residuals

        adf = adfuller(residuals)

        return adf[1], slope, intercept, z_index, standard_dev_residuals
#region imports
from AlgorithmImports import *
#endregion
from AlgorithmImports import *
import numpy as np
import statsmodels.api as model
from statsmodels.tsa.stattools import adfuller

# This code implements the pairs trading algorithm detailed in the lecture notes.  Credit to the authors.
# The method of calculating the ADF is modified from code on slide 162 of lecture 8.  Credit to the authors.


class Math585HW(QCAlgorithm):

    
    def Initialize(self):
        self.p = "GOOG"
        self.q = "MS"

        self.AddEquity(self.p, Resolution.Daily)
        self.AddEquity(self.q, Resolution.Daily)
        
        self.SetStartDate(2018, 1, 1)  
        self.SetEndDate(2020, 1, 1) 
        self.SetCash(100000)
        self.SetWarmup(150)

 
        # Amount of market positions I want to take in total
        self.C = 10000

        self.lookback_window = 150 #days

        #self.beta = 0.5624042647804646
        #self.alpha = 2.718503876069648 
        #self.sigma = 0.020898581545820503

        self.Debug("In Init")

    def OnData(self, data):

        if self.IsWarmingUp:
            return

        p_px = self.Securities[self.p].Price
        q_px = self.Securities[self.q].Price
 
        hist_p = self.History([self.p], self.lookback_window, resolution=Resolution.Daily)["close"].tolist()
        hist_q = self.History([self.q], self.lookback_window, resolution=Resolution.Daily)["close"].tolist()
        _, beta, alpha, _, sigma = self.calc_adf(hist_p, hist_q)

        residual = np.log(p_px) - np.log(q_px) * beta - alpha

        z_idx = residual / sigma

        entrythreshold = 1
        exitthreshold = 0.7

        wtp = 1 / (1 + beta)
        wtq = beta / (1 + beta)


        msg = f"-----\nResidual = {residual}\nZ_index = {z_idx}"
        self.Debug(msg)

        #if not self.Portfolio[self.p].Invested:
        if not self.Portfolio[self.p].IsLong and not self.Portfolio[self.p].IsShort:
            if z_idx > entrythreshold:
                self.MarketOrder(self.p, -wtp*self.C/p_px)
                self.MarketOrder(self.q, wtq*self.C/q_px)
            elif z_idx < -entrythreshold:
                self.MarketOrder(self.p, wtp*self.C/p_px)
                self.MarketOrder(self.q, -wtq*self.C/q_px)

            
        elif self.Portfolio[self.p].IsLong:

            if z_idx >= 0:
                self.Liquidate(self.p)
                self.Liquidate(self.q)


        elif self.Portfolio[self.p].IsShort:
            if z_idx <= 0:
                self.Liquidate(self.p)
                self.Liquidate(self.q)


    def calc_adf(self, close1, close2):
        # This method of calculating the ADF is modified from code on slide 162 of lecture 8.  Credit to the authors.
        logclose1 = np.log(close1)
        logclose2 = np.log(close2)
    
        ind = model.add_constant(logclose1)
        dep = logclose2

        leastsquare = model.OLS(dep, ind)
        prod = leastsquare.fit()

        slope = prod.params[1]
        intercept = prod.params[0]
        residuals = prod.resid
        standard_dev_residuals = np.sqrt(prod.mse_resid)

        # Residuals are mean zero. Therefore the z-index is simply observation over std dev.
        z_index = residuals / standard_dev_residuals

        adf = adfuller(residuals)

        return adf[1], slope, intercept, z_index, standard_dev_residuals
#region imports
from AlgorithmImports import *
#endregion
from AlgorithmImports import *
import numpy as np

# This code implements the pairs trading algorithm detailed in the lecture notes.  Credit to the authors.

class Math585HW(QCAlgorithm):

    
    def Initialize(self):
        self.SetStartDate(2018, 1, 1)  
        self.SetEndDate(2020, 1, 1) 
        self.SetCash(1000000)


        self.p = "BRK.B"
        self.q = "BAC"

        self.AddEquity(self.p, Resolution.Daily)
        self.AddEquity(self.q, Resolution.Daily)

        self.beta = 0.34557999277780166
        self.alpha = 1.4501248536931102
        self.sigma = 0.06514845048594146


    def OnData(self, data):

        self.Debug(f"In OnData")

        p_px = self.Securities[self.p].Price
        q_px = self.Securities[self.q].Price

        self.Debug(f"P price: {p_px}; Q price: {q_px}")

        residual = np.log(p_px) - np.log(q_px) * self.beta - self.alpha
        self.Debug(residual)
        z_idx = residual / self.sigma

        entrythreshold = 2
        exitthreshold = 0

        wtp = 1 / (1 + self.beta)
        wtq = self.beta / (1 + self.beta)
        C = 1000000

        self.Debug(f"Z-idx = {z_idx}")

        # Risk Management Condition:
        if np.abs(z_idx) > 3:
            self.Liquidate(self.p)
            self.Liquidate(self.q)
            

        #if not self.Portfolio[self.p].Invested:
        if not self.Portfolio[self.p].IsLong and not self.Portfolio[self.p].IsShort:
            if z_idx > entrythreshold:
                self.MarketOrder(self.p, -wtp*C/p_px)
                self.MarketOrder(self.q, wtq*C/q_px)
            elif z_idx < -entrythreshold:
                self.MarketOrder(self.p, wtp*C/p_px)
                self.MarketOrder(self.q, -wtq*C/q_px)

            
        elif self.Portfolio[self.p].IsLong:

            if z_idx >= 0:
                self.Liquidate(self.p)
                self.Liquidate(self.q)


        elif self.Portfolio[self.p].IsShort:
            if z_idx <= 0:
                self.Liquidate(self.p)
                self.Liquidate(self.q)
#region imports
from AlgorithmImports import *
#endregion
from AlgorithmImports import *
import numpy as np
import statsmodels.api as model
from statsmodels.tsa.stattools import adfuller
from datetime import timedelta
import math

# This code implements the pairs trading algorithm detailed in the lecture notes.  Credit to the authors.
# The method of calculating the ADF is modified from code on slide 162 of lecture 8.  Credit to the authors.


class Math585HW(QCAlgorithm):

    
    def Initialize(self):
        self.p = "GOOG"
        self.q = "MS"

        self.res = Resolution.Hour

        self.AddEquity(self.p, self.res)
        self.AddEquity(self.q, self.res)
        
        self.SetStartDate(2019, 6, 1)  
        self.SetEndDate(2020, 1, 1) 
        self.SetCash(100000)
        self.SetWarmup(150)

 
        # Amount of capitol I want to risk
        # The remainder of my cash will remain cash.
        self.C = 10000

        self.lookback_window = 150 #days

        self.Debug("In Init")

        #TOTO change
        self.start = True

        self.quit = False

    def OnMarginCallWarning(self):
        self.Debug("Liquidating due to Margin Call concern")
        self.quit = True
        self.SetHoldings(self.p, 0)
        self.SetHoldings(self.q, 0)

    def OnData(self, data):
        self.Log("In OnData")
        if self.IsWarmingUp:
            self.Log("Warming Up")
            return

        if self.start:
            #Gauarantee a starting purchase to make sure I have at least one trade no matter what the market does.
            self.Debug("Starting")
            self.start = False
            self.SetHoldings(self.p, 0.05)
            self.SetHoldings(self.q, -0.05)
            return


        if self.quit:
            return

        # Safety Check against Margin call
        if self.Portfolio.MarginRemaining < 0.1 * self.Portfolio.TotalPortfolioValue:
            self.Debug("Liquidating due to Margin Call concern")
            self.quit = True
            self.SetHoldings(self.p, 0)
            self.SetHoldings(self.q, 0)

        try:
            p_px = self.Securities[self.p].Price
            q_px = self.Securities[self.q].Price
 
            hist_p = self.History([self.p], timedelta(days=self.lookback_window), resolution=self.res)["close"].tolist()
            hist_q = self.History([self.q], timedelta(days=self.lookback_window), resolution=self.res)["close"].tolist()
            #self.Debug(hist_p)
            _, beta, alpha, z_indices, sigma = self.calc_adf(hist_p, hist_q)

            residual = 0
            z_idx = z_indices[-1]

            entrythreshold = 1
            exitthreshold = 0.7

            wtp = 1 / (1 + beta)
            wtq = beta / (1 + beta)

            self.Debug(f"LT: Z_index: {z_idx}")

            #if not self.Portfolio[self.p].Invested:
            if not self.Portfolio[self.p].IsLong and not self.Portfolio[self.p].IsShort:
                if z_idx > entrythreshold:
                    self.Debug("Opening Short Position")
                    self.MarketOrder(self.p, math.floor(-wtp*self.C/p_px))
                    self.MarketOrder(self.q, math.ceil(wtq*self.C/q_px))
                elif z_idx < -entrythreshold:
                    self.Debug("Opening Long Position")
                    self.MarketOrder(self.p, math.ceil(wtp*self.C/p_px))
                    self.MarketOrder(self.q, math.floor(-wtq*self.C/q_px))
            
            elif self.Portfolio[self.p].IsLong:

                if z_idx > -exitthreshold:
                    self.Debug("Closing Position")
                    self.SetHoldings(self.p, 0)
                    self.SetHoldings(self.q, 0)

            elif self.Portfolio[self.p].IsShort:
                if z_idx < exitthreshold:
                    self.Debug("Closing Position")
                    self.SetHoldings(self.p, 0)
                    self.SetHoldings(self.q, 0)
            
        except Error as e:
            self.Debug("Caught an error; prevented code from crashing")
            return


    def calc_adf(self, close1, close2):
        # This method of calculating the ADF is modified from code on slide 162 of lecture 8.  Credit to the authors.
        logclose1 = np.log(close1)
        logclose2 = np.log(close2)
    
        ind = model.add_constant(logclose1)
        dep = logclose2

        leastsquare = model.OLS(dep, ind)
        prod = leastsquare.fit()

        slope = prod.params[1]
        intercept = prod.params[0]
        residuals = prod.resid
        standard_dev_residuals = np.sqrt(prod.mse_resid)

        # Residuals are mean zero. Therefore the z-index is simply observation over std dev.
        z_index = residuals / standard_dev_residuals

        #adf = adfuller(residuals)

        return None, slope, intercept, z_index, standard_dev_residuals
#region imports
from AlgorithmImports import *
#endregion
from AlgorithmImports import *

class Math585HW(QCAlgorithm):

    def Initialize(self):
        self.AddEquity("SPY")
        self.AddEquity("MS")
        self.AddEquity("XOM")
        self.SetStartDate(2017, 1, 1)  
        self.SetEndDate(2018, 1, 1) 
        self.SetCash(1000000)
        self.SetWarmup(30)

        self.first_day = True

        self.xom_wt = 0.5
        self.spy_wt = 0
        self.ms_wt = 0.5


    def OnData(self, data):

        if self.IsWarmingUp:
            return

        if self.first_day:
            self.first_day = False
            self.SetHoldings("MS", self.ms_wt)
            self.SetHoldings("XOM", self.xom_wt)
            self.SetHoldings("SPY", self.spy_wt)
#region imports
from AlgorithmImports import *
#endregion
from AlgorithmImports import *
import numpy as np

"""
This code was built off of a template provided by Lecture 12 on Sakai.  Credit to the authors.

This code also follows the approach of https://www.quantconnect.com/learning/articles/introduction-to-options/quantconnect-options-api
Credit to the authors.
"""

class Math585HW(QCAlgorithm):
    def Initialize(self) -> None:

        self.option_pos_size = 3600

        self.SetStartDate(2021, 11, 1)
        self.SetEndDate(2021, 11, 19)
        self.SetCash(2000000)
        self.SetWarmUp(25)
        # Requesting data
        self.underlying = self.AddEquity("QQQ").Symbol
        option = self.AddOption("QQQ")
        self.option_symbol = option.Symbol

        # Set our strike/expiry filter for this option chain
        option.SetFilter(0, 5, 0, 90)
        self.contract = None
        #Set Options Model: Equity Options are American Style
        # As such, need to use CrankNicolsonFD or other models. 
        #BlackScholes Model is only for European Options
        option.PriceModel = OptionPriceModels.CrankNicolsonFD()

        self.day1 = True
        self.historic = []

    def OnData(self, slice: Slice) -> None:
        self.Debug(f"in OnData")
        if self.IsWarmingUp: #Wait until warming up is done
            self.historic.append(self.Securities["QQQ"].Price)
            return

        # On Day 1, we need to identify: 
        # - the ATM contract
        # - whether we are longing or shorting this contract
        if self.day1 == True:
            self.day1=False

            # Calculate volatility over the past 25 days:
            self.historic = self.historic[-25:]

            self.Debug(f"Historic: {self.historic}")
            # Calc log returns
            logret = []
            for i in range(1, len(self.historic)):
                logret.append(self.historic[i] / self.historic[i-1])

            hist_vol = np.std(logret)

            self.Debug(f"Historic Volatility: {hist_vol}")

            # Find the ATM option:
            todayprice = self.Securities["QQQ"].Price
            chain = slice.OptionChains.get(self.option_symbol)
            if chain:
                self.Debug("In Chain")
                # Select call contracts
                expiry = datetime(2021, 11, 19)
                correct_right = [contract for contract in chain if contract.Right == OptionRight.Call]
                correct_expiry = [contract for contract in correct_right if contract.Expiry == expiry]
                good_strike = [contract for contract in correct_expiry if contract.Strike > todayprice]

                # Search through available options to find the one with the lowest strike price in range:
                best_option = good_strike[0]
                best_strike = good_strike[0].Strike
                for i in range(len(good_strike)):
                    if good_strike[i].Strike < best_strike:
                        best_option = good_strike[i]
                        best_strike = good_strike[i].Strike

                self.atm = best_option
                self.Debug(f"There are {len(correct_expiry)} options that match!")
                self.Debug(f"Best option is {self.atm}")

                ivol = self.atm.ImpliedVolatility
                self.Debug(f"Implied Volatility is: {ivol}")

                # Long or short option?
                if ivol < hist_vol:
                    self.long_option = -1
                else:
                    self.long_option = 1

                self.Debug(f"Delta: {self.atm.Greeks.Delta}")

                # Order the option in the correct quantity and direction
                self.MarketOrder(self.atm.Symbol, self.option_pos_size * self.long_option)
                self.last_delta = self.atm.Greeks.Delta

            else:
                # Not Day 1 work

                # Code heavily based upon Pranay Jain (TA)'s Ed Post
                # Credit to the source.

                new_delta = self.atm.Greeks.Delta
                hedge = self.option_pos_size * self.long_option * 100 *  (new_delta - self.last_delta)
                self.MarketOrder("QQQ", hedge)
                self.last_delta = new_delta



            

            


#region imports
from AlgorithmImports import *
#endregion
from AlgorithmImports import *

"""
This code was built off of a template provided by Lecture 12 on Sakai.  Credit to the authors.

This code also follows the approach of https://www.quantconnect.com/learning/articles/introduction-to-options/quantconnect-options-api
Credit to the authors.
"""

class Math585HW(QCAlgorithm):
    def Initialize(self) -> None:
        self.SetStartDate(2022, 10, 14)
        self.SetEndDate(2023, 1, 1)
        self.SetCash(100000)
        self.SetWarmUp(20)
        # Requesting data
        self.underlying = self.AddEquity("AAPL").Symbol
        option = self.AddOption("AAPL")
        self.option_symbol = option.Symbol
        # Set our strike/expiry filter for this option chain
        option.SetFilter(-20, 4, 15, 30)
        self.contract = None
        #Set Options Model: Equity Options are American Style
        # As such, need to use CrankNicolsonFD or other models. 
        #BlackScholes Model is only for European Options
        option.PriceModel = OptionPriceModels.CrankNicolsonFD()

    def OnData(self, slice: Slice) -> None:
        self.Debug(f"in OnData")
        if self.IsWarmingUp: #Wait until warming up is done
            return
        if self.Portfolio[self.underlying].Invested:
            self.Liquidate(self.underlying)

        if self.contract is not None and self.Portfolio[self.contract.Symbol].Invested:
            return

        chain = slice.OptionChains.get(self.option_symbol)
        if chain:
            self.Debug("In Chain")
            # Select call contracts
            correct_right = [contract for contract in chain if contract.Right == OptionRight.Call]
            if len(correct_right) == 0:
                return

            
            self.Debug(f"Length Nonzero {correct_right[0].Strike}")

            strike = 145
            # expiry = "2022-11-18"
            expiry = datetime(2022, 11, 18)
            """
            # Select the call contracts with the furthest expiration
            furthest_expiry = sorted(correct_right, key = lambda x: x.Expiry, reverse=True)[0].Expiry
            furthest_expiry_calls = [contract for contract in calls if contract.Expiry == furthest_expiry]
            # From the remaining contracts, select the one with its strike closest to the underlying price
            self.contract = sorted(furthest_expiry_calls, key = lambda x: abs(chain.Underlying.Price - x.Strike))[0]
            """

            strikes = []

            for x in correct_right:
                if x.Strike not in strikes:
                    strikes.append(x.Strike)

                if x.Strike == strike and x.Expiry == expiry:
                    self.contract = x
                    break

            if self.contract is None:
                self.Debug("No contract me the requirements")
                return

            ivol = self.contract.ImpliedVolatility
            self.Debug("+++++++++++++++++")
            self.Debug("Implied Vol: " + str(ivol)) 
            self.Debug("Ask Price: " + str(self.contract.AskPrice))
            self.Debug("+++++++++++++++++")
            self.Debug(strikes)
            self.MarketOrder(self.contract.Symbol, 1)
#region imports
from AlgorithmImports import *
#endregion
from AlgorithmImports import *

"""
Much of this code was built off of a template provided by Lecture 12 on Sakai.  Credit to the authors.

This code also follows the approach of https://www.quantconnect.com/learning/articles/introduction-to-options/quantconnect-options-api
Credit to the authors.
"""

class Math585HW(QCAlgorithm):
    def Initialize(self) -> None:
        self.SetStartDate(2022, 10, 14)
        self.SetEndDate(2023, 1, 1)
        self.SetCash(100000)
        self.SetWarmUp(20)
        # Requesting data
        self.underlying = self.AddEquity("AAPL").Symbol
        option = self.AddOption("AAPL")
        self.option_symbol = option.Symbol
        # Set our strike/expiry filter for this option chain
        option.SetFilter(-30, -10, 15, 30)
        self.contract = None
        #Set Options Model: Equity Options are American Style
        # As such, need to use CrankNicolsonFD or other models. 
        #BlackScholes Model is only for European Options
        option.PriceModel = OptionPriceModels.CrankNicolsonFD()

    def OnData(self, slice: Slice) -> None:
        self.Debug(f"in OnData")
        if self.IsWarmingUp: #Wait until warming up is done
            return
        if self.Portfolio[self.underlying].Invested:
            self.Liquidate(self.underlying)

        if self.contract is not None and self.Portfolio[self.contract.Symbol].Invested:
            return

        chain = slice.OptionChains.get(self.option_symbol)
        if chain:
            self.Debug("In Chain")
            # Select call contracts
            correct_right = [contract for contract in chain if contract.Right == OptionRight.Put]
            if len(correct_right) == 0:
                return

            
            self.Debug(f"Length Nonzero {correct_right[0].Strike}")

            strike = 130
            # expiry = "2022-11-18"
            expiry = datetime(2022, 11, 18)
            """
            # Select the call contracts with the furthest expiration
            furthest_expiry = sorted(correct_right, key = lambda x: x.Expiry, reverse=True)[0].Expiry
            furthest_expiry_calls = [contract for contract in calls if contract.Expiry == furthest_expiry]
            # From the remaining contracts, select the one with its strike closest to the underlying price
            self.contract = sorted(furthest_expiry_calls, key = lambda x: abs(chain.Underlying.Price - x.Strike))[0]
            """

            strikes = []

            for x in correct_right:
                if x.Strike not in strikes:
                    strikes.append(x.Strike)

                if x.Strike == strike and x.Expiry == expiry:
                    self.contract = x
                    break

            if self.contract is None:
                self.Debug("No contract me the requirements")
                return

            ivol = self.contract.ImpliedVolatility
            self.Debug("+++++++++++++++++")
            self.Debug("Implied Vol: " + str(ivol)) 
            self.Debug("Ask Price: " + str(self.contract.AskPrice))
            self.Debug("+++++++++++++++++")
            self.Debug(strikes)
            self.MarketOrder(self.contract.Symbol, 1)
#region imports
from AlgorithmImports import *
#endregion
from AlgorithmImports import *

"""
Much of this code was built off of a template provided by Lecture 12 on Sakai.  Credit to the authors.

This code also follows the approach of https://www.quantconnect.com/learning/articles/introduction-to-options/quantconnect-options-api
Credit to the authors.
"""

class Math585HW(QCAlgorithm):
    def Initialize(self) -> None:
        self.SetStartDate(2022, 10, 14)
        self.SetEndDate(2023, 1, 1)
        self.SetCash(100000)
        self.SetWarmUp(20)
        # Requesting data
        self.underlying = self.AddEquity("AAPL").Symbol
        option = self.AddOption("AAPL")
        self.option_symbol = option.Symbol
        # Set our strike/expiry filter for this option chain
        option.SetFilter(-30, -10, 30, 90)
        self.contract = None
        #Set Options Model: Equity Options are American Style
        # As such, need to use CrankNicolsonFD or other models. 
        #BlackScholes Model is only for European Options
        option.PriceModel = OptionPriceModels.CrankNicolsonFD()

    def OnData(self, slice: Slice) -> None:
        self.Debug(f"in OnData")
        if self.IsWarmingUp: #Wait until warming up is done
            return
        if self.Portfolio[self.underlying].Invested:
            self.Liquidate(self.underlying)

        if self.contract is not None and self.Portfolio[self.contract.Symbol].Invested:
            return

        chain = slice.OptionChains.get(self.option_symbol)
        if chain:
            self.Debug("In Chain")
            # Select call contracts
            correct_right = [contract for contract in chain if contract.Right == OptionRight.Put]
            if len(correct_right) == 0:
                return

            
            self.Debug(f"Length Nonzero {correct_right[0].Expiry}")

            # expiry = "2022-11-18"
            expiry = datetime(2022, 12, 16)
            """
            # Select the call contracts with the furthest expiration
            furthest_expiry = sorted(correct_right, key = lambda x: x.Expiry, reverse=True)[0].Expiry
            furthest_expiry_calls = [contract for contract in calls if contract.Expiry == furthest_expiry]
            # From the remaining contracts, select the one with its strike closest to the underlying price
            self.contract = sorted(furthest_expiry_calls, key = lambda x: abs(chain.Underlying.Price - x.Strike))[0]
            """

            strikes = []

            for x in correct_right:
                #self.Debug(f"Expiry: {x.Expiry} Strike: {x.Strike}")

                if x.Strike == 125 and x.Expiry == expiry:
                    self.contract125 = x
                    break

            for x in correct_right:
                #self.Debug(f"Expiry: {x.Expiry} Strike: {x.Strike}")

                if x.Strike == 130 and x.Expiry == expiry:
                    self.contract130 = x
                    break


            self.Debug("+++++++++++++++++")
            self.Debug("125 - Implied Vol: " + str(self.contract125.ImpliedVolatility)) 
            self.Debug("125 - Ask Price: " + str(self.contract125.AskPrice))
            self.Debug("130 - Implied Vol: " + str(self.contract130.ImpliedVolatility)) 
            self.Debug("130 - Ask Price: " + str(self.contract130.AskPrice))
            self.Debug("+++++++++++++++++")
            self.Debug(strikes)
            self.MarketOrder(self.contract.Symbol, 1)

            # To prevent errors
            self.contract = self.contract130
# region imports
from AlgorithmImports import *
# endregion

class Math585HW(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2020, 1, 1)  # Set Start Date
        self.SetEndDate(2021, 1, 1)
        self.SetCash(1000000)  # Set Strategy Cash
        
        self.AddEquity("AMZN", Resolution.Daily)
        self.AddEquity("GOOG", Resolution.Daily)

    
        self.GOOG_POS = 6000
        self.AMZN_POS = -8000
        self.init_run = True

    def OnData(self, data: Slice):

        # On first call to OnData, do the following:
        if self.init_run:
            self.init_run = False
            print("Placing Market ORder")
            self.MarketOrder("GOOG", self.GOOG_POS)
            self.MarketOrder("AMZN", self.AMZN_POS)
# region imports
from AlgorithmImports import *
# endregion

class Math585HW(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2020, 1, 1)  # Set Start Date
        self.SetEndDate(2021, 1, 1)
        self.SetCash(1000000)  # Set Strategy Cash
        
        self.AddEquity("AMZN", Resolution.Daily)
        self.AddEquity("GOOG", Resolution.Daily)

    
        self.GOOG_POS = 6000
        self.AMZN_POS = -8000
        self.init_run = True

    def OnData(self, data: Slice):

        # On first call to OnData, do the following:
        if self.init_run:
            self.init_run = False
            print("Placing Market ORder")
            self.MarketOrder("GOOG", self.GOOG_POS)
            self.MarketOrder("AMZN", self.AMZN_POS)

    
        # On subsequent days, do the following:
        else:
            if self.Portfolio.TotalUnrealizedProfit < -100000:
                self.MarketOrder("GOOG", -self.GOOG_POS)
                self.MarketOrder("AMZN", -self.AMZN_POS)
# region imports
from AlgorithmImports import *
# endregion

class Math585HW(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2020, 1, 1)  # Set Start Date
        self.SetEndDate(2021, 1, 1)
        self.SetCash(1000000)  # Set Strategy Cash
        
        self.AddEquity("AMZN", Resolution.Daily)
        self.AddEquity("GOOG", Resolution.Daily)

    
        self.GOOG_POS = 6000
        self.AMZN_POS = -8000
        self.init_run = True

    def OnData(self, data: Slice):
        
        # On first call to OnData, do the following:
        if self.init_run:
            self.init_run = False
            print("Placing Limit Order")
            self.LimitOrder("GOOG", self.GOOG_POS, self.Securities["GOOG"].Price * 0.95)
            self.LimitOrder("AMZN", self.AMZN_POS, self.Securities["AMZN"].Price * 1.05)

    
        # On subsequent days, do the following:
        else:
            if self.Portfolio.TotalUnrealizedProfit < -100000:
                self.MarketOrder("GOOG", -self.GOOG_POS)
                self.MarketOrder("AMZN", -self.AMZN_POS)
# region imports
from AlgorithmImports import *
# endregion

class Math585HW(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2020, 1, 1)  # Set Start Date
        self.SetEndDate(2021, 1, 1)
        self.SetCash(1000000)  # Set Strategy Cash
        
        self.AddEquity("AMZN", Resolution.Daily)
        self.AddEquity("GOOG", Resolution.Daily)

    
        self.GOOG_POS = 4221
        self.AMZN_POS = -(8/6) * self.GOOG_POS
        
        self.init_run = True

    def OnData(self, data: Slice):

        # On first call to OnData, do the following:
        if self.init_run:
            self.init_run = False
            print("Placing Limit Order")
            self.Debug(f"Longing {self.GOOG_POS} google shares and Shorting {self.AMZN_POS} amazon shares")
            self.MarketOrder("GOOG", self.GOOG_POS)
            self.MarketOrder("AMZN", self.AMZN_POS)

    def OnMarginCall(self, r):
        # Make sure that the user cannot miss the fact that a margin call occured.
        # If a margin call occurs, an assertion error will pop up.
        assert False
#region imports
from AlgorithmImports import *
#endregion
from AlgorithmImports import *

"""
Much of this code was built off of a template provided by Lecture 12 on Sakai.  Credit to the authors.

This code also follows the approach of https://www.quantconnect.com/learning/articles/introduction-to-options/quantconnect-options-api
Credit to the authors.
"""

class Math585HW(QCAlgorithm):
    def Initialize(self) -> None:
        self.SetStartDate(2022, 10, 14)
        self.SetEndDate(2023, 1, 1)
        self.SetCash(100000)
        self.SetWarmUp(20)
        # Requesting data
        self.underlying = self.AddEquity("AAPL").Symbol
        option = self.AddOption("AAPL")
        self.option_symbol = option.Symbol
        # Set our strike/expiry filter for this option chain
        option.SetFilter(-30, -10, 15, 30)
        self.contract = None
        #Set Options Model: Equity Options are American Style
        # As such, need to use CrankNicolsonFD or other models. 
        #BlackScholes Model is only for European Options
        option.PriceModel = OptionPriceModels.CrankNicolsonFD()

    def OnData(self, slice: Slice) -> None:
        self.Debug(f"in OnData")
        if self.IsWarmingUp: #Wait until warming up is done
            return
        if self.Portfolio[self.underlying].Invested:
            self.Liquidate(self.underlying)

        if self.contract is not None and self.Portfolio[self.contract.Symbol].Invested:
            return

        chain = slice.OptionChains.get(self.option_symbol)
        if chain:
            self.Debug("In Chain")
            # Select call contracts
            correct_right = [contract for contract in chain if contract.Right == OptionRight.Put]
            if len(correct_right) == 0:
                return

            
            self.Debug(f"Length Nonzero {correct_right[0].Strike}")

            strike = 130
            # expiry = "2022-11-18"
            expiry = datetime(2022, 11, 18)
            """
            # Select the call contracts with the furthest expiration
            furthest_expiry = sorted(correct_right, key = lambda x: x.Expiry, reverse=True)[0].Expiry
            furthest_expiry_calls = [contract for contract in calls if contract.Expiry == furthest_expiry]
            # From the remaining contracts, select the one with its strike closest to the underlying price
            self.contract = sorted(furthest_expiry_calls, key = lambda x: abs(chain.Underlying.Price - x.Strike))[0]
            """

            strikes = []

            for x in correct_right:
                if x.Strike not in strikes:
                    strikes.append(x.Strike)

                if x.Strike == strike and x.Expiry == expiry:
                    self.contract = x
                    break

            if self.contract is None:
                self.Debug("No contract me the requirements")
                return

            ivol = self.contract.ImpliedVolatility
            self.Debug("+++++++++++++++++")
            self.Debug("Implied Vol: " + str(ivol)) 
            self.Debug("Ask Price: " + str(self.contract.AskPrice))
            self.Debug("+++++++++++++++++")
            self.Debug(strikes)
            self.MarketOrder(self.contract.Symbol, 1)