| Overall Statistics |
|
Total Trades 3 Average Win 0.51% Average Loss -0.58% Compounding Annual Return -0.328% Drawdown 1.300% Expectancy -0.058 Net Profit -0.070% Sharpe Ratio -0.112 Probabilistic Sharpe Ratio 27.157% Loss Rate 50% Win Rate 50% Profit-Loss Ratio 0.88 Alpha -0.019 Beta 0.057 Annual Standard Deviation 0.019 Annual Variance 0 Information Ratio -1.564 Tracking Error 0.186 Treynor Ratio -0.037 Total Fees $2.00 Estimated Strategy Capacity $34000000.00 Lowest Capacity Asset AAPL Y3LLKBUVNGBQ|AAPL R735QTJ8XC9X Portfolio Turnover 0.39% |
#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 starting from code provided by Lecture 12 on Sakai. Credit to the authors.
This code also follows the approach of and some code from 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 starting from code provided by Lecture 12 on Sakai. Credit to the authors.
This code also follows the approach of and some code from 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 *
"""
This code was built starting from code provided by Lecture 12 on Sakai. Credit to the authors.
This code also follows the approach of and some code from 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 *
"""
This code was built starting from code provided by Lecture 12 on Sakai. Credit to the authors.
This code also follows the approach of and some code from 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 *
"""
This code was built starting from code provided by Lecture 12 on Sakai. Credit to the authors.
This code also follows the approach of and some code from 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)