Overall Statistics |
Total Trades 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Net Profit 0% Sharpe Ratio 0 Probabilistic Sharpe Ratio 0% Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio -0.859 Tracking Error 0.207 Treynor Ratio 0 Total Fees $0.00 Estimated Strategy Capacity $0 Lowest Capacity Asset Portfolio Turnover 0% |
# region imports from AlgorithmImports import * from math import log, sqrt, pi, exp from scipy.stats import norm import scipy.stats as stats # endregion ## ------------------------ Assignment 1 AAPL Contracts info class FatYellowOwl(QCAlgorithm): def Initialize(self) -> None: self.SetStartDate(2022, 7, 14) self.SetEndDate(2022, 12, 1) self.SetCash(100000) self.SetWarmUp(20) # Universe settings self.UniverseSettings.Resolution = Resolution.Hour # Requesting data self.aapl = self.AddEquity("AAPL",Resolution.Hour).Symbol option = self.AddOption("AAPL",Resolution.Hour) self.option_symbol = option.Symbol # Volatility self.last_price = RollingWindow[float](2) self.std = StandardDeviation(25) # Risk Free rate self.yieldCurve = self.AddData(USTreasuryYieldCurveRate, "USTYCR", Resolution.Daily).Symbol self.last_rfr = RollingWindow[float](4) #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() ## ----------- Black Scholes ------------- ## # Price def bsm_price(self, option_type, sigma, s, k, r, T, q): # calculate the bsm price of European call and put options d1 = (np.log(s / k) + (r - q + sigma ** 2 * 0.5) * T) / (sigma * np.sqrt(T)) d2 = d1 - sigma * np.sqrt(T) if option_type == 'c': return np.exp(-r*T) * (s * np.exp((r - q)*T) * stats.norm.cdf(d1) - k * stats.norm.cdf(d2)) if option_type == 'p': return np.exp(-r*T) * (k * stats.norm.cdf(-d2) - s * np.exp((r - q)*T) * stats.norm.cdf(-d1)) raise Exception(f'No such option type: {option_type}') def implied_vol(self, option_type, option_price, s, k, r, T, q): # apply bisection method to get the implied volatility by solving the BSM function precision = 0.00001 upper_vol = 500.0 max_vol = 500.0 min_vol = 0.0001 lower_vol = 0.0001 iteration = 50 while iteration > 0: iteration -= 1 mid_vol = (upper_vol + lower_vol)/2 price = self.bsm_price(option_type, mid_vol, s, k, r, T, q) if option_type == 'c': lower_price = self.bsm_price(option_type, lower_vol, s, k, r, T, q) if (lower_price - option_price) * (price - option_price) > 0: lower_vol = mid_vol else: upper_vol = mid_vol if mid_vol > max_vol - 5 : return 0.000001 if option_type == 'p': upper_price = self.bsm_price(option_type, upper_vol, s, k, r, T, q) if (upper_price - option_price) * (price - option_price) > 0: upper_vol = mid_vol else: lower_vol = mid_vol if abs(price - option_price) < precision: break return mid_vol def OnData(self, data: Slice) -> None: if data.get(self.yieldCurve): self.last_rfr.Add(data[self.yieldCurve].OneYear) if self.Time.hour == 10 and data.get(self.aapl): # Once per day self.last_price.Add(data[self.aapl].Price) if self.last_price.IsReady: self.std.Update(self.Time, (self.last_price[0]-self.last_price[1])/self.last_price[1]) if self.IsWarmingUp: #Wait until warming up is done return if self.Time == datetime(2022,10,14,15): rfr = self.last_rfr[0] vol = self.std.Current.Value*sqrt(252) T = abs(self.Time - datetime(2022,11,18)).days/365 # Compute the price for the call option price = self.bsm_price('c',vol,data[self.aapl].Price, 145, rfr, T, 0) # Get the Implied volatility based on computed price implied_volatility = self.implied_vol('c', price, data[self.aapl].Price, 145,rfr, T, 0) self.Log(f'At{self.Time} a Call option on AAPL with strike price 145 and expiry of 2022-11-18 has a price {price} and implied volatility {implied_volatility}') elif self.Time == datetime(2022,10,17,10): rfr = self.last_rfr[0] vol = self.std.Current.Value*sqrt(252) T = abs(self.Time - datetime(2022,11,11)).days # Compute the price for the call option price = self.bsm_price('p',vol,data[self.aapl].Price, 145, rfr, T, 0) # Get the Implied volatility based on computed price implied_volatility = self.implied_vol('p', price, data[self.aapl].Price, 145,rfr, T, 0) self.Log(f'At{self.Time} a Put option on AAPL with strike price 130 and expiry of 2022-11-11 has a price {price} and implied volatility {implied_volatility}') elif self.Time == datetime(2022,10,17,13): self.interpolate_contract(data) def interpolate_contract(self,data): computed_prices = [None] computed_impvol = [None] deltas_t = [datetime(2022,12,16)] rfr = self.last_rfr[0] vol = self.std.Current.Value*sqrt(252) # Because we are using +- this will be month approximatly for i in range(10): delta_t_minus = abs(self.Time - (datetime(2022,12,16)-timedelta(days=i))).days delta_t_plus = abs(self.Time - (datetime(2022,12,16)+timedelta(days=i))).days deltas_t = [datetime(2022,12,16)+timedelta(days=i)] + deltas_t deltas_t.append(datetime(2022,12,16)+timedelta(days=i)) # Compute the price and Implied volatility for the put option price = self.bsm_price('p', vol, data[self.aapl].Price, 145, rfr, delta_t_minus, 0) implied_volatility = self.implied_vol('p', price, data[self.aapl].Price, 145,rfr, delta_t_minus, 0) computed_prices = [price] + computed_prices computed_impvol = [implied_volatility] + computed_impvol # Compute the price and Implied volatility for the put option price = self.bsm_price('p', vol, data[self.aapl].Price, 145, rfr, delta_t_plus, 0) implied_volatility = self.implied_vol('p', price, data[self.aapl].Price, 145,rfr, delta_t_plus, 0) computed_prices.append(price) computed_impvol.append(implied_volatility) my_data = pd.DataFrame({'Price':computed_prices,'Implied_Volatility': computed_impvol}, index=deltas_t) intepolated = my_data.interpolate() self.Log(f'At {self.Time} the interpolated value for price and implied volatility with expiry 2022-12-16 is {str(intepolated.iloc[10])}') self.Log(f'The three previous values are {str(intepolated.iloc[7:10])}') self.Log(f'The three following values are {str(intepolated.iloc[11:14])}') # class FatYellowOwl(QCAlgorithm): # def Initialize(self) -> None: # self.SetStartDate(2022, 9, 14) # self.SetEndDate(2022, 12, 1) # self.SetCash(100000) # self.SetWarmUp(20) # # Universe settings # self.UniverseSettings.Resolution = Resolution.Hour # # Requesting data # self.aapl = self.AddEquity("AAPL",Resolution.Hour).Symbol # option = self.AddOption("AAPL",Resolution.Hour) # self.option_symbol = option.Symbol # # Volatility # self.std = StandardDeviation(22) # self.RegisterIndicator(self.aapl, self.std, Resolution.Daily) # # Risk Free rate # self.yieldCurve = self.AddData(USTreasuryYieldCurveRate, "USTYCR", Resolution.Daily).Symbol # self.last_rfr = RollingWindow[float](4) # # OTCM contracts # self.otc = self.AddEquity("OTCM",Resolution.Hour).Symbol # option = self.AddOption("OTCM",Resolution.Hour) # self.otc_symbol = option.Symbol # #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() # ## ----------- Black Scholes ------------- ## # # Price # def d1(self,S,K,T,r,sigma): # return(log(S/K)+(r+sigma**2/2.)*T)/(sigma*sqrt(T)) # def d2(self,S,K,T,r,sigma): # return self.d1(S,K,T,r,sigma)-sigma*sqrt(T) # def bs_call(self,S,K,T,r,sigma): # return S*norm.cdf(self.d1(S,K,T,r,sigma))-K*exp(-r*T)*norm.cdf(self.d2(S,K,T,r,sigma)) # def bs_put(self,S,K,T,r,sigma): # return K*exp(-r*T)-S*self.bs_call(S,K,T,r,sigma) # # Implied Volatility # def call_implied_volatility(self,Price, S, K, T, r): # sigma = 0.001 # while sigma < 1: # Price_implied = S * \ # norm.cdf(self.d1(S, K, T, r, sigma))-K*exp(-r*T) * \ # norm.cdf(self.d2(S, K, T, r, sigma)) # if Price-(Price_implied) < 0.001: # return sigma # sigma += 0.001 # return "Not Found" # def put_implied_volatility(self,Price, S, K, T, r): # sigma = 0.001 # while sigma < 1: # Price_implied = K*exp(-r*T)-S+self.bs_call(S, K, T, r, sigma) # if Price-(Price_implied) < 0.001: # return sigma # sigma += 0.001 # return "Not Found" # def OnData(self, data: Slice) -> None: # if data.get(self.yieldCurve): # self.last_rfr.Add(data[self.yieldCurve].OneYear) # if self.IsWarmingUp: #Wait until warming up is done # return # if self.Time == datetime(2022,10,14,15): # rfr = self.last_rfr[0] # # Compute the price for the call option # price = self.bs_call(data[self.aapl].Price, 145, abs(self.Time - datetime(2022,11,18)).days, rfr, self.std.Current.Value*sqrt(252)) # # Get the Implied volatility based on computed price # implied_volatility = self.call_implied_volatility(price, 145, abs(self.Time - datetime(2022,11,18)).days, rfr, self.std.Current.Value*sqrt(252)) # self.Log(f'At{self.Time} a Call option on AAPL with strike price 145 and expiry of 2022-11-18 has a price {price} and implied volatility {implied_volatility}') # elif self.Time == datetime(2022,10,17,10): # rfr = self.last_rfr[0] # # Compute the price for the put option # price = self.bs_put(data[self.aapl].Price, 130, abs(self.Time - datetime(2022,11,11)).days, rfr, self.std.Current.Value*sqrt(252)) # # Get the Implied volatility based on computed price # implied_volatility = self.put_implied_volatility(price, 130, abs(self.Time - datetime(2022,11,11)).days, rfr, self.std.Current.Value*sqrt(252)) # self.Log(f'At{self.Time} a Put option on AAPL with strike price 130 and expiry of 2022-11-11 has a price {price} and implied volatility {implied_volatility}') # elif self.Time == datetime(2022,10,17,13): # self.otc_contract(data) # def otc_contract(self,data): # computed_prices = [None] # computed_impvol = [None] # deltas_t = [datetime(2022,12,16)] # rfr = self.last_rfr[0] # # Because we are using +- this will be month approximatly # for i in range(10): # delta_t_minus = abs(self.Time - (datetime(2022,12,16)-timedelta(days=i))).days # delta_t_plus = abs(self.Time - (datetime(2022,12,16)+timedelta(days=i))).days # deltas_t = [datetime(2022,12,16)+timedelta(days=i)] + deltas_t # deltas_t.append(datetime(2022,12,16)+timedelta(days=i)) # # Compute the price and Implied volatility for the put option # price = self.bs_put(data[self.aapl].Price, 128.25, delta_t_minus, rfr, self.std.Current.Value*sqrt(252)) # implied_volatility = self.put_implied_volatility(price, 130, delta_t_minus, rfr, self.std.Current.Value*sqrt(252)) # computed_prices = [price] + computed_prices # computed_impvol = [implied_volatility] + computed_impvol # # Compute the price and Implied volatility for the put option # price = self.bs_put(data[self.aapl].Price, 128.25, delta_t_plus, rfr, self.std.Current.Value*sqrt(252)) # implied_volatility = self.put_implied_volatility(price, 130, delta_t_plus, rfr, self.std.Current.Value*sqrt(252)) # computed_prices.append(price) # computed_impvol.append(implied_volatility) # my_data = pd.DataFrame({'Price':computed_prices,'Implied_Volatility': computed_impvol}, index=deltas_t) # intepolated = my_data.interpolate() # self.Log(f'At {self.Time} the interpolated value for price and implied volatility with expiry 2022-12-16 is {str(intepolated.iloc[10])}') # self.Log(f'The three previous values are {str(intepolated.iloc[7:10])}') # self.Log(f'The three following values are {str(intepolated.iloc[11:14])}') ## ------------------------ Assignment 2