| Overall Statistics |
|
Total Trades 50 Average Win 0.94% Average Loss -0.84% Compounding Annual Return 890.528% Drawdown 6.000% Expectancy 0.240 Net Profit 12.002% Sharpe Ratio 12.223 Probabilistic Sharpe Ratio 85.286% Loss Rate 42% Win Rate 58% Profit-Loss Ratio 1.12 Alpha 2.949 Beta 4.944 Annual Standard Deviation 0.389 Annual Variance 0.151 Information Ratio 12.712 Tracking Error 0.345 Treynor Ratio 0.961 Total Fees $1900.31 Estimated Strategy Capacity $160000.00 Lowest Capacity Asset QQQ XTN6UBU4F61Y|QQQ RIWIV7K5Z9LX Portfolio Turnover 59.05% |
# region imports
from AlgorithmImports import *
# endregion
class EnergeticYellowGreenGiraffe(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2020,1,1)
self.SetEndDate(2021,1,1)
self.SetCash(1000000)
# add securities
self.AddEquity("GOOG", Resolution.Daily)
self.GOOG = self.Symbol("GOOG")
self.AddEquity("AMZN", Resolution.Daily)
self.AMZN = self.Symbol("AMZN")
self.count = 0
def OnData(self, data: Slice):
if self.count == 0:
self.MarketOrder("GOOG", 6000)
self.MarketOrder("AMZN",-8000)
value = self.Portfolio.TotalPortfolioValue
self.Log('Portfolio Value : ' + str(value))
self.count += 1
if value < 900000:
order_ids = self.Liquidate()
# region imports
from AlgorithmImports import *
# endregion
class EnergeticYellowGreenGiraffe(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2020,1,1)
self.SetEndDate(2021,1,1)
self.SetCash(1000000)
# add securities
self.AddEquity("GOOG", Resolution.Daily)
self.AddEquity("AMZN", Resolution.Daily)
def OnData(self, data: Slice):
# get starting date prices
if self.Time.day == 1 and self.Time.month == 1 and self.Time.year == 2020:
self.AMZN_start = self.Securities["AMZN"].Price
self.GOOG_start = self.Securities["GOOG"].Price
self.LimitOrder("AMZN", -8000, 1.05 * self.AMZN_start)
self.LimitOrder("GOOG", 6000, 0.95 * self.GOOG_start)
value = self.Portfolio.TotalPortfolioValue
if value < 900000:
order_ids = self.Liquidate()
value = self.Portfolio.TotalPortfolioValue
if value < 900000:
order_ids = self.Liquidate()# region imports
from AlgorithmImports import *
# endregion
class MeasuredTanJackal(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2020,1,1)
self.SetEndDate(2021,1,1)
self.SetCash(1000000)
# add securities
self.AddEquity("GOOG", Resolution.Daily)
self.AddEquity("AMZN", Resolution.Daily)
self.amzn_orders = -5628
self.goog_orders = round(self.amzn_orders * 3/4,0)
def OnData(self, data: Slice):
self.Debug(f"AMZN : {self.amzn_orders} \n GOOG : {self.goog_orders}")
if self.Time.day == 1 and self.Time.year == 2020 and self.Time.month == 1:
self.MarketOrder("AMZN", self.amzn_orders)
self.MarketOrder("GOOG", -self.goog_orders)# region imports
from AlgorithmImports import *
# endregion
class EnergeticYellowGreenGiraffe(QCAlgorithm):
"""
1. (5 pts) Compute the Sharpe Ratio of a buy-and-hold strategy for each of the above stocks
individually for the given time period, that is, you need to compute four
Sharpe Ratios separately, one for each stock.
"""
def Initialize(self):
self.SetStartDate(2019,2,1)
self.SetEndDate(2021,2,1)
self.SetCash(1000000)
#self.AddEquity('GS', Resolution.Daily)
#self.AddEquity('MS', Resolution.Daily)
#self.AddEquity('AMD', Resolution.Daily)
self.AddEquity('XOM', Resolution.Daily)
def OnData(self, data: Slice):
#self.SetHoldings('GS', 1)
#self.SetHoldings('MS', 1)
#self.SetHoldings('AMD', 1)
self.SetHoldings('XOM', 1)
# region imports
from AlgorithmImports import *
# endregion
class EnergeticYellowGreenGiraffe(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2019,2,1)
self.SetEndDate(2021,2,1)
self.SetCash(1000000)
# just commenting and uncommenting the below to find the statistic for
# the relevant ticker
#self.AddEquity('GS', Resolution.Daily)
self.AddEquity('MS', Resolution.Daily)
#self.AddEquity('AMD', Resolution.Daily)
#self.AddEquity('XOM', Resolution.Daily)
self.count = 0
def OnData(self, data: Slice):
if self.count == 0:
#self.SetHoldings('GS', 1)
self.SetHoldings('MS', 1)
#self.SetHoldings('AMD', 1)
#self.SetHoldings('XOM', 1)
value = self.Portfolio.TotalUnrealizedProfit
stop_loss = 0.07 * 1000000
self.count += 1
# with 1MM starting value, equates to losing or gaining $70,000
if (value <= -stop_loss) or (value >= stop_loss):
order = self.Liquidate()# region imports
from AlgorithmImports import *
# endregion
class EnergeticYellowGreenGiraffe(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2019,2,1)
self.SetEndDate(2021,2,1)
self.SetCash(1000000)
# just commenting and uncommenting the below to find the statistic for
# the relevant ticker
self.AddEquity('GS', Resolution.Daily)
self.AddEquity('MS', Resolution.Daily)
#self.AddEquity('AMD', Resolution.Daily)
#self.AddEquity('XOM', Resolution.Daily)
self.count = 0
def OnData(self, data: Slice):
if self.count == 0:
self.SetHoldings('GS', 0.5)
self.SetHoldings('MS', -0.5)
#self.SetHoldings('AMD', 1)
#self.SetHoldings('XOM', 1)
self.count += 1
# region imports
from AlgorithmImports import *
# endregion
class EnergeticYellowGreenGiraffe(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2019,2,1)
self.SetEndDate(2021,2,1)
self.SetCash(1000000)
# just commenting and uncommenting the below to find the statistic for
# the relevant ticker
self.AddEquity('GS', Resolution.Daily)
self.AddEquity('MS', Resolution.Daily)
self.AddEquity('AMD', Resolution.Daily)
self.AddEquity('XOM', Resolution.Daily)
self.count = 0
def OnData(self, data: Slice):
if self.count == 0:
self.SetHoldings('GS', 0.25)
self.SetHoldings('MS', -0.25)
self.SetHoldings('AMD', 0.25)
self.SetHoldings('XOM', -.25)
self.count += 1
#region imports
from AlgorithmImports import *
#endregion
class EnergeticYellowGreenGiraffe(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2019,8,20)
self.SetEndDate(2020,7,20)
self.SetCash(2000000)
self.ticker ='ROKU'
self.sym = self.AddEquity(self.ticker, Resolution.Daily) #S1
self.sma = self.SMA(self.ticker, 20, Resolution.Daily)
self.port = False
if self.port:
self.wt = 0.25 # if we have two stocks, each wt will be 25%
else:
self.wt = 0.5 # single stock wt 50%
def OnData(self, data: Slice):
ind = self.sma.Current.Value
if not self.Portfolio[self.ticker].Invested:
if self.sym.Price > ind:
self.SetHoldings(self.sym.Symbol, self.wt)
elif self.sym.Price < ind:
self.SetHoldings(self.sym.Symbol, -self.wt)
elif (self.Portfolio[self.ticker].IsLong and self.sym.Price< ind) or (self.Portfolio[self.ticker].IsShort and self.sym.Price> ind):
self.SetHoldings(self.sym.Symbol, 0.0)
#region imports
from AlgorithmImports import *
#endregion
class EnergeticYellowGreenGiraffe(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2019,8,20)
self.SetEndDate(2020,7,20)
self.SetCash(2000000)
self.ticker1 ='AMD'
self.sym1 = self.AddEquity(self.ticker1, Resolution.Daily) #S1
self.sma = self.SMA(self.ticker1, 20, Resolution.Daily)
self.port = False
if self.port:
self.wt = 0.25 # if we have two stocks, each wt will be 25%
else:
self.wt = 0.5 # single stock wt 50%
def OnData(self, data: Slice):
ind1 = self.sma.Current.Value
if not self.Portfolio[self.ticker1].Invested:
if self.sym1.Price > ind1:
self.SetHoldings(self.sym1.Symbol, -self.wt)
elif self.sym1.Price < ind1:
self.SetHoldings(self.sym1.Symbol, self.wt)
elif self.Portfolio[self.ticker1].IsLong and self.sym1.Price< ind1 or self.Portfolio[self.ticker1].IsShort and self.sym1.Price> ind1:
self.SetHoldings(self.sym1.Symbol, 0.0)
# region imports
from AlgorithmImports import *
# endregion
class EnergeticYellowGreenGiraffe(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2019,8,20)
self.SetEndDate(2020,7,20)
self.SetCash(2000000)
self.ticker1 ='ROKU'
self.sym1 = self.AddEquity(self.ticker1, Resolution.Daily) #S1
self.sma1 = self.SMA(self.ticker1, 20, Resolution.Daily)
self.ticker2 = 'AMD'
self.sym2 = self.AddEquity(self.ticker2, Resolution.Daily) #S2
self.sma2 = self.SMA(self.ticker2, 20, Resolution.Daily)
self.port = True
if self.port:
self.wt = 0.25 # if we have two stocks, each wt will be 25%
else:
self.wt = 0.5 # single stock wt 50%
def OnData(self, data: Slice):
ind1 = self.sma1.Current.Value
ind2 = self.sma2.Current.Value
self.Debug("Price1 " + str(self.sym1.Price) + "indicator " +str(ind1))
self.Debug("Price2 " + str(self.sym2.Price) + "indicator " +str(ind2))
if not self.Portfolio[self.ticker1].Invested:
if self.sym1.Price > ind1:
self.SetHoldings(self.sym1.Symbol, self.wt)
elif self.sym1.Price < ind1:
self.SetHoldings(self.sym1.Symbol, -self.wt)
elif self.Portfolio[self.ticker1].IsLong and self.sym1.Price< ind1 or \
self.Portfolio[self.ticker1].IsShort and self.sym1.Price> ind1:
self.SetHoldings(self.sym1.Symbol, 0.0)
#Trend-reversal Strategy for self.ticker1
if self.port:
if not self.Portfolio[self.ticker2].Invested:
if self.sym2.Price > ind2:
self.SetHoldings(self.sym2.Symbol, -self.wt)
elif self.sym2.Price <ind2:
self.SetHoldings(self.sym2.Symbol, self.wt)
elif self.Portfolio[self.ticker2].IsLong and self.sym2.Price< ind2 or \
self.Portfolio[self.ticker2].IsShort and self.sym2.Price> ind2:
self.SetHoldings(self.sym2.Symbol, 0.0)
#region imports
from AlgorithmImports import *
#endregion
import numpy as np
import pandas as pd
from datetime import timedelta, datetime
import math
import statsmodels.api as sm
from statsmodels.tsa.stattools import coint, adfuller
class PairsTradingAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetCash(100000)
self.enter = 2 # Set the enter threshold
self.exit = 0 # Set the exit threshold
self.lookback = 20 # Set the loockback period 90 days
self.pairs =['MSFT','GOOG']
self.symbols =[]
for ticker in self.pairs:
self.AddEquity(ticker, Resolution.Hour)
self.symbols.append(self.Symbol(ticker))
self.sym1 = self.pairs[0]
self.sym2 = self.pairs[1]
def stats(self, symbols):
#Use Statsmodels package to compute linear regression and ADF statistics
self.df = self.History(symbols, self.lookback)
self.dg = self.df["open"].unstack(level=0)
#self.Debug(self.dg)
ticker1= str(symbols[0])
ticker2= str(symbols[1])
Y = self.dg[ticker1].apply(lambda x: math.log(x))
X = self.dg[ticker2].apply(lambda x: math.log(x))
X = sm.add_constant(X)
model = sm.OLS(Y,X)
results = model.fit()
sigma = math.sqrt(results.mse_resid) # standard deviation of the residual
slope = results.params[1]
intercept = results.params[0]
res = results.resid #regression residual mean of res =0 by definition
zscore = res/sigma
adf = adfuller (res)
return [adf, zscore, slope]
def OnData(self, data):
margin = self.Portfolio.MarginRemaining
self.Log(f"margin remaining : {margin}")
# margin risk management
if margin <= 20000:
self.Liquidate()
self.IsInvested = (self.Portfolio[self.sym1].Invested) or (self.Portfolio[self.sym2].Invested)
self.ShortSpread = self.Portfolio[self.sym1].IsShort
self.LongSpread = self.Portfolio[self.sym1].IsLong
try:
stats = self.stats([self.sym1, self.sym2])
except:
stats = (1,(1,1),1) # placeholder for exception in calc
self.beta = stats[2]
zscore= stats[1][-1]
self.wt1 = 1/(1+self.beta)
self.wt2 = self.beta/(1+self.beta)
self.pos1 = self.Portfolio[self.sym1].Quantity
self.px1 = self.Portfolio[self.sym1].Price
self.pos2 = self.Portfolio[self.sym2].Quantity
self.px2 = self.Portfolio[self.sym2].Price
self.equity =self.Portfolio.TotalPortfolioValue
if self.IsInvested:
if self.ShortSpread and zscore <= self.exit or \
self.LongSpread and zscore >= self.exit or \
zscore >= 3:
self.Liquidate()
else:
if zscore > self.enter:
self.SetHoldings(self.sym1, -self.wt1)
self.SetHoldings(self.sym2, self.wt2)
if zscore < - self.enter:
self.SetHoldings(self.sym1, self.wt1)
self.SetHoldings(self.sym2, -self.wt2)
self.pos1 = self.Portfolio[self.sym1].Quantity
self.pos2 = self.Portfolio[self.sym2].Quantity
# region imports
from AlgorithmImports import *
# endregion
class EnergeticYellowGreenGiraffe(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2018,1,1)
self.SetEndDate(2018,1,5)
self.SetCash(1000000)
self.AddUniverse(self.Coarse, self.Fine)
self.UniverseSettings.Resolution = Resolution.Daily
self.SetSecurityInitializer(lambda x: x.SetDataNormalizationMode(DataNormalizationMode.Raw))
def Coarse(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 Fine(self, fine):
fine1 = [x for x in fine if x.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.FinancialServices]
sortedByMarketCap = sorted(fine1, key=lambda c: c.MarketCap, reverse=True)
self.filter_fine = [i.Symbol for i in sortedByMarketCap][0:3]
return self.filter_fine
def OnData(self, data: Slice):
self.Log(f"OnData({self.UtcTime}): Keys: {', '.join([key.Value for key in data.Keys])}")
import statsmodels.api as sm
from statsmodels.tsa.stattools import coint, adfuller
# region imports
from AlgorithmImports import *
# endregion
class EnergeticYellowGreenGiraffe(QCAlgorithm):
def Initialize(self):
self.lookback = 60
self.SetStartDate(2018,1,1)
self.SetEndDate(2019,1,1)
self.SetCash(1000000)
self.enter = 2 # Set the enter threshold
self.exit = 0 # Set the exit threshold
self.lookback = 90 # Set the loockback period 90 days
# BAC, BRK.B, JPM
self.pairs =['JPM','BAC']
self.ticker1 = self.pairs[0]
self.ticker2 = self.pairs[1]
self.AddEquity(self.ticker1, Resolution.Daily)
self.AddEquity(self.ticker2, Resolution.Daily)
self.symbols = [self.Symbol(self.ticker1), self.Symbol(self.ticker2)]
# borrowing code presented in class, lecture 8 p. 162
def stats(self, symbols):
#symbols is a pair of QC Symbol Object
self.df = self.History(symbols, self.lookback)
self.dg = self.df["open"].unstack(level=0)
Y = self.dg[self.ticker1].apply(lambda x: math.log(x))
X = self.dg[self.ticker2].apply(lambda x: math.log(x))
X = sm.add_constant(X)
model = sm.OLS(Y,X)
results = model.fit()
sigma = math.sqrt(results.mse_resid) #standard deviation of the residual
slope = results.params[1]
intercept = results.params[0]
res = results.resid #regression residual has mean =0 by definition
zscore = res/sigma
adf = adfuller(res)
return [adf, zscore, slope]
def OnData(self, data: Slice):
# get the adf and the actual adf score per the docs
adf = self.stats(self.symbols)[0]
self.Log(f"ADF for {self.ticker1} and {self.ticker2} : {adf[0]}; p-value : {adf[1]}")#region imports
from AlgorithmImports import *
#endregion
import numpy as np
import pandas as pd
from datetime import timedelta, datetime
import math
import statsmodels.api as sm
from statsmodels.tsa.stattools import coint, adfuller
class EnergeticYellowGreenGiraffe(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2018,1,1)
self.SetEndDate(2019,1,1)
self.SetCash(1000000)
self.enter = 2
self.exit = 0
self.lookback = 20
# BAC, BRK.B, JPM
self.pairs =['JPM','BAC']
self.ticker1 = self.pairs[0]
self.ticker2 = self.pairs[1]
self.AddEquity(self.ticker1, Resolution.Daily)
self.AddEquity(self.ticker2, Resolution.Daily)
self.symbols = [self.Symbol(self.ticker1), self.Symbol(self.ticker2)]
self.sym1 = self.symbols[0]
self.sym2 = self.symbols[1]
# borrowing code presented in class, lecture 8 p. 162
def stats(self, symbols):
#symbols is a pair of QC Symbol Object
self.df = self.History(symbols, self.lookback)
self.dg = self.df["open"].unstack(level=0)
Y = self.dg[self.ticker1].apply(lambda x: math.log(x))
X = self.dg[self.ticker2].apply(lambda x: math.log(x))
X = sm.add_constant(X)
model = sm.OLS(Y,X)
results = model.fit()
sigma = math.sqrt(results.mse_resid) #standard deviation of the residual
slope = results.params[1]
intercept = results.params[0]
res = results.resid #regression residual has mean =0 by definition
zscore = res/sigma
adf = adfuller(res)
return [adf, zscore, slope]
def OnData(self, data):
self.IsInvested = (self.Portfolio[self.sym1].Invested) or (self.Portfolio[self.sym2].Invested)
self.ShortSpread = self.Portfolio[self.sym1].IsShort
self.LongSpread = self.Portfolio[self.sym1].IsLong
stats = self.stats([self.sym1, self.sym2])
self.beta = stats[2]
zscore= stats[1][-1]
self.wt1 = 1/(1+self.beta)
self.wt2 = self.beta/(1+self.beta)
self.pos1 = self.Portfolio[self.sym1].Quantity
self.px1 = self.Portfolio[self.sym1].Price
self.pos2 = self.Portfolio[self.sym2].Quantity
self.px2 = self.Portfolio[self.sym2].Price
self.equity =self.Portfolio.TotalPortfolioValue
if self.IsInvested:
if self.ShortSpread and zscore <= self.exit or \
self.LongSpread and zscore >= self.exit:
self.Liquidate()
else:
if zscore > self.enter:
self.SetHoldings(self.sym1, -self.wt1)
self.SetHoldings(self.sym2, self.wt2)
if zscore < -self.enter:
self.SetHoldings(self.sym1, self.wt1)
self.SetHoldings(self.sym2, -self.wt2)
self.pos1 = self.Portfolio[self.sym1].Quantity
self.pos2 = self.Portfolio[self.sym2].Quantity#region imports
from AlgorithmImports import *
#endregion
import numpy as np
import pandas as pd
from datetime import timedelta, datetime
import math
import statsmodels.api as sm
from statsmodels.tsa.stattools import coint, adfuller
class EnergeticYellowGreenGiraffe(QCAlgorithm):
def Initialize(self):
self.lookback = 60
self.SetStartDate(2018,1,1)
self.SetEndDate(2019,1,1)
self.SetCash(1000000)
self.enter = 2
self.exit = 0
self.lookback = 20
# BAC, BRK.B, JPM
self.pairs =['JPM','BAC']
self.ticker1 = self.pairs[0]
self.ticker2 = self.pairs[1]
self.AddEquity(self.ticker1, Resolution.Daily)
self.AddEquity(self.ticker2, Resolution.Daily)
self.symbols = [self.Symbol(self.ticker1), self.Symbol(self.ticker2)]
self.sym1 = self.symbols[0]
self.sym2 = self.symbols[1]
# borrowing code presented in class, lecture 8 p. 162
def stats(self, symbols):
#symbols is a pair of QC Symbol Object
self.df = self.History(symbols, self.lookback)
self.dg = self.df["open"].unstack(level=0)
Y = self.dg[self.ticker1].apply(lambda x: math.log(x))
X = self.dg[self.ticker2].apply(lambda x: math.log(x))
X = sm.add_constant(X)
model = sm.OLS(Y,X)
results = model.fit()
sigma = math.sqrt(results.mse_resid) #standard deviation of the residual
slope = results.params[1]
intercept = results.params[0]
res = results.resid #regression residual has mean =0 by definition
zscore = res/sigma
adf = adfuller(res)
return [adf, zscore, slope]
def OnData(self, data):
self.IsInvested = (self.Portfolio[self.sym1].Invested) or (self.Portfolio[self.sym2].Invested)
self.ShortSpread = self.Portfolio[self.sym1].IsShort
self.LongSpread = self.Portfolio[self.sym2].IsLong
stats = self.stats([self.sym1, self.sym2])
self.beta = stats[2]
zscore= stats[1][-1]
abs_z = abs(zscore)
self.wt1 = 1/(1+self.beta)
self.wt2 = self.beta/(1+self.beta)
self.pos1 = self.Portfolio[self.sym1].Quantity
self.px1 = self.Portfolio[self.sym1].Price
self.pos2 = self.Portfolio[self.sym2].Quantity
self.px2 = self.Portfolio[self.sym2].Price
self.equity =self.Portfolio.TotalPortfolioValue
if self.IsInvested:
if self.ShortSpread and zscore <= self.exit or \
self.LongSpread and zscore >= self.exit or \
abs_z > 3:
self.Liquidate()
else:
if zscore > self.enter:
self.SetHoldings(self.sym1, -self.wt1)
self.SetHoldings(self.sym2, self.wt2)
if zscore < -self.enter:
self.SetHoldings(self.sym1, self.wt1)
self.SetHoldings(self.sym2, -self.wt2)
self.pos1 = self.Portfolio[self.sym1].Quantity
self.pos2 = self.Portfolio[self.sym2].Quantity
self.Debug(f"z-score : {zscore}; abs z-score : {abs_z}")#region imports
from AlgorithmImports import *
#endregion
"""
(10 pts) Demonstrate Portfolio Diversification Benefits - Start with $1M and perform backtest
over the same time period in #1. Let SR[TICKER] denote the Sharpe Ratio of a buy-and-hold strategy
of a stock with the ticker symbol TICKER. Let 0.5MS+0.5XOM denote the portfolio for equal weights
in MS and XOM. Also, SPY is the ETF for S&P market index. Test the validity of the Equation (2)
on slide 194 by computing the Sharpe Ratios of the four buy-hold strategies below and explain
why your answers make sense.
"""
class PairsTradingAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2017,1,1)
self.SetEndDate(2018,1,1)
self.SetCash(1000000)
self.pairs =['SPY']
self.symbols =[]
for ticker in self.pairs:
self.AddEquity(ticker, Resolution.Daily)
self.symbols.append(self.Symbol(ticker))
self.sym1 = self.pairs[0]
def OnData(self, data):
if not self.Portfolio.Invested:
self.SetHoldings(self.sym1, 1)
# region imports
from AlgorithmImports import *
# endregion
# Ref: https://www.quantconnect.com/docs/v2/research-environment/datasets/equity-options
class FormalBlackAnguilline(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2022, 10, 14)
self.SetEndDate(2022, 10, 17)
self.SetCash(100000) # Set Strategy Cash
spy = self.AddEquity("QQQ", Resolution.Hour)
self.symbol = spy.Symbol
contracts = [
Symbol.CreateOption(self.symbol, Market.USA, OptionStyle.American, OptionRight.Put, 130, datetime(2022, 11, 11)),
Symbol.CreateOption(self.symbol, Market.USA, OptionStyle.American, OptionRight.Call, 145, datetime(2022, 11, 18))
]
for contract in contracts:
option = self.AddOptionContract(contract, Resolution.Hour)
option.PriceModel = OptionPriceModels.BjerksundStensland()
self.df = pd.DataFrame()
def OnData(self, data: Slice):
equity = self.Securities[self.symbol]
for canonical_symbol, chain in data.OptionChains.items():
for contract in chain:
greeks = contract.Greeks
data = {
"IV" : contract.ImpliedVolatility,
"Delta": greeks.Delta,
"Gamma": greeks.Gamma,
"Vega": greeks.Vega,
"Rho": greeks.Rho,
"Theta": greeks.Theta,
"LastPrice": contract.LastPrice,
"Close": self.Securities[contract.Symbol].Close,
"theoreticalPrice" : contract.TheoreticalPrice,
"underlyingPrice": equity.Close
}
symbol = contract.Symbol
right = "Put" if symbol.ID.OptionRight == 1 else "Call"
index = pd.MultiIndex.from_tuples([(symbol.ID.Date, symbol.ID.StrikePrice, right, symbol.Value, self.Time)], names=["expiry", "strike", "type", "symbol", "endTime"])
self.df = pd.concat([self.df, pd.DataFrame(data, index=index)])
def OnEndOfAlgorithm(self):
self.ObjectStore.Save("price-models/backtest-df", self.df.sort_index().to_csv())# region imports
from AlgorithmImports import *
# endregion
# Ref: https://www.quantconnect.com/docs/v2/research-environment/datasets/equity-options
# https://www.quantconnect.com/docs/v2/writing-algorithms/securities/asset-classes/equity-options/requesting-data
class FormalBlackAnguilline(QCAlgorithm):
def Initialize(self):
# given parameters
self.SetStartDate(2021, 11, 1)
self.SetEndDate(2021, 11, 2) # change back to 19
self.SetCash(2000000)
self.lookback = 25
option = self.AddOption('QQQ', resolution=Resolution.Hour)
equity = self.AddEquity('QQQ', resolution=Resolution.Hour)
self.option_symbol = option.Symbol
option.SetFilter(-1, +1)
def stats(self, symbols):
self.df = self.History('QQQ', self.lookback)
self.dg = self.df["open"].unstack(level=0).diff().dropna()
sigma = math.sqrt(self.dg)
return sigma
def OnData(self,slice):
chain = slice.OptionChains.get(self.option_symbol)
if chain:
# get the contract
call = [x for x in chain if x.Right == OptionRight.Call] # get calls
contract = sorted(call, key = lambda x: abs(chain.Underlying.Price - x.Strike))[0] # get ATM
# get info about the contract
delta = contract.Greeks.Delta
symbol = contract.Symbol
# calculate volatility
sigma = self.stats
# short or long based on that
self.MarketOrder(symbol, 1)
self.MarketOnCloseOrder(symbol, -1)
def OnOrderEvent(self, orderEvent):
self.Log(f'{orderEvent}')
def OnEndOfAlgorithm(self):
data = self.History('QQQ', 25)
self.ObjectStore.Save("will_df", data.sort_index().to_csv())
import numpy as np
from AlgorithmImports import *
# Ref: https://www.quantconnect.com/docs/v2/research-environment/datasets/equity-options
# https://www.quantconnect.com/docs/v2/writing-algorithms/securities/asset-classes/equity-options/requesting-data
class FormalBlackAnguilline(QCAlgorithm):
def Initialize(self):
# given parameters
self.SetStartDate(2021, 11, 1)
self.SetEndDate(2021, 11, 18)
self.SetCash(2000000)
self.lookback = 25
option = self.AddOption('QQQ', resolution=Resolution.Daily)
self.equity = self.AddEquity('QQQ', Resolution.Daily).Symbol
self.option_symbol = option.Symbol
option.SetFilter(-1, +1)
def stats(self):
self.df = self.History(self.equity, self.lookback)
self.dg = self.df["open"].unstack(level=0).pct_change().dropna()
sigma = np.std(self.dg) * 10 # to annualize the 25-day chunks
return sigma[0]
def OnData(self,slice):
chain = slice.OptionChains.get(self.option_symbol)
if chain:
# get the contract
call = [x for x in chain if x.Right == OptionRight.Call] # get calls
contract = sorted(call, key = lambda x: abs(chain.Underlying.Price - x.Strike))[0] # get ATM
# get info about the contract
delta = contract.Greeks.Delta
iv = contract.ImpliedVolatility
symbol = contract.Symbol
# order sizing
option_weight = 0.05
qqq_quantity = (option_weight * 2000000) / (100 * delta)
self.Debug(f"quantity : {qqq_quantity}")
# calculate volatility
sigma = self.stats()
if sigma > iv:
self.Liquidate()
self.SetHoldings(symbol, -option_weight)
self.Buy('QQQ', qqq_quantity)
else:
self.Liquidate()
self.SetHoldings(symbol, option_weight)
self.Buy('QQQ', -qqq_quantity)
def OnOrderEvent(self, orderEvent):
self.Log(f'{orderEvent}')
#region imports
from AlgorithmImports import *
#endregion
import numpy as np
import pandas as pd
from datetime import timedelta, datetime
import math
import statsmodels.api as sm
from statsmodels.tsa.stattools import coint, adfuller
class PairsTradingAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2021, 6, 1)
self.SetEndDate(2022,8,1)
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
self.SetCash(100000)
self.pairs =['GOOG','MSFT']
self.symbols =[]
for ticker in self.pairs:
self.AddEquity(ticker, Resolution.Daily)
self.symbols.append(self.Symbol(ticker))
self.sym1 = self.symbols[0]
self.sym2 = self.symbols[1]
def OnData(self, data):
margin = self.Portfolio.MarginRemaining
self.Log(f"margin remaining : {margin}")
if margin <= .25 * 100000:
self.Liquidate()
if not self.Portfolio.Invested:
self.SetHoldings('GOOG',-2)