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)