def GreeksFunc(self, option, process): try: if self.product.exercise_type == 'E': engine = ql.AnalyticEuropeanEngine(process) option.setPricingEngine(engine) Greeks = pd.DataFrame([option.delta(),option.gamma(),option.vega()/100,option.theta()/365,option.rho()/100], columns = [''], \ index=['Delta','Gamma','Vega(%)','ThetaPerDay','Rho(%)']) elif self.product.exercise_type == 'A': #用BaroneAdesiWhaley离散法计算Greeks engine = ql.BaroneAdesiWhaleyEngine(process) #engine = ql.BinomialVanillaEngine(process, "crr", 100) #BTM option.setPricingEngine(engine) Greeks = self.Numerical_Greeks(option) else: raise ValueError #传入的参数self.product.exercise_type 无效 #缺少解析解时用离散法蒙特卡洛模拟,计算Greeks except: engine = ql.MCDiscreteArithmeticAPEngine( process, self.product.mc_str, self.product.is_bb, self.product.is_av, self.product.is_cv, self.product.n_require, self.product.tolerance, self.product.n_max, self.product.seed) option.setPricingEngine(engine) Greeks = self.Numerical_Greeks(option) # ============================================================================= # #无论亚美还是亚欧都一样 # engine = ql.MCDiscreteArithmeticAPEngine(process, self.product.mc_str, self.product.is_bb, self.product.is_av, self.product.is_cv, self.product.n_require, self.product.tolerance, self.product.n_max, self.product.seed) # option.setPricingEngine(engine) # Greeks = self.Numerical_Greeks(option) #进入离散法计算Greeks # ============================================================================= return Greeks
def reset_vol(self, vol): self.flat_vol_ts = ql.BlackVolTermStructureHandle( ql.BlackConstantVol(self.settlement, self.calendar, vol, self.day_count)) self.bsm_process = ql.BlackScholesMertonProcess( self.spot_handle, self.dividend_yield, self.flat_ts, self.flat_vol_ts) engine = ql.BaroneAdesiWhaleyEngine(self.bsm_process) self.ql_option.setPricingEngine(engine)
def GreeksFunc(self, option, process): if self.exercise_type == 'E': engine = ql.AnalyticEuropeanEngine(process) option.setPricingEngine(engine) Greeks = pd.DataFrame([option.delta(),option.gamma(),option.vega()/100,option.theta()/365,option.rho()/100],\ index=['Delta','Gamma','Vega(%)','ThetaPerDay','Rho(%)']) elif self.exercise_type == 'A': #用离散法计算Greeks engine = ql.BaroneAdesiWhaleyEngine(process) #engine = ql.BinomialVanillaEngine(process, "crr", 100) #BTM option.setPricingEngine(engine) #Delta Gamma u0 = self.underlying_price.value() p0 = option.NPV() h = 0.01 #dS self.underlying_price.setValue(u0 + h) p_plus = option.NPV() #print(p_plus) self.underlying_price.setValue(u0 - h) p_minus = option.NPV() self.underlying_price.setValue(u0) delta = (p_plus - p_minus) / (2 * h) gamma = (p_plus - 2 * p0 + p_minus) / (h * h) #Vega v0 = self.volatility.value() h = 0.1 self.volatility.setValue(v0 + h) print(self.volatility.value()) p_plus = option.NPV() print(p_plus) self.volatility.setValue(v0) vega = (p_plus - p0) / h #Theta ql.Settings.instance().evaluationDate = self.vDate + 1 p1 = option.NPV() h = 1 / 365.0 theta = (p1 - p0) / h ql.Settings.instance().evaluationDate = self.vDate #Rho r0 = self.interest_rate.value() h = 0.0001 self.interest_rate.setValue(r0 + h) p_plus = option.NPV() self.interest_rate.setValue(r0) rho = (p_plus - p0) / h Greeks = pd.DataFrame([delta,gamma,vega/100,theta/365,rho/100],\ index=['Delta','Gamma','Vega(%)','ThetaPerDay','Rho(%)']) else: pass return Greeks
def __init__(self, dt_eval: datetime.date, dt_maturity: datetime.date, option_type: constant.OptionType, option_exercise_type: constant.OptionExerciseType, spot: float, strike: float, vol: float = 0.2, rf: float = 0.03, n: int = 801, dividend_rate: float = 0.0): super().__init__() self.values: typing.List[typing.List[float]] = [] self.asset_values: typing.List[typing.List[float]] = [] self.exercise_values: typing.List[typing.List[float]] = [] self.strike = strike self.spot = spot self.vol = vol self.rf = rf self.dividend_rate = dividend_rate self.steps: int = n self.maturity_date = constant.QuantlibUtil.to_ql_date(dt_maturity) self.settlement = constant.QuantlibUtil.to_ql_date(dt_eval) ql.Settings.instance().evaluationDate = self.settlement if option_type == constant.OptionType.PUT: self.option_type = ql.Option.Put else: self.option_type = ql.Option.Call payoff = ql.PlainVanillaPayoff(self.option_type, strike) if option_exercise_type == constant.OptionExerciseType.AMERICAN: self.exercise = ql.AmericanExercise(self.settlement, self.maturity_date) self.ql_option = ql.VanillaOption(payoff, self.exercise) else: self.exercise = ql.EuropeanExercise(self.maturity_date) self.ql_option = ql.VanillaOption(payoff, self.exercise) self.day_count = ql.ActualActual() self.calendar = ql.China() self.spot_handle = ql.QuoteHandle(ql.SimpleQuote(spot)) self.flat_ts = ql.YieldTermStructureHandle( ql.FlatForward(self.settlement, rf, self.day_count)) self.dividend_yield = ql.YieldTermStructureHandle( ql.FlatForward(self.settlement, self.dividend_rate, self.day_count)) self.flat_vol_ts = ql.BlackVolTermStructureHandle( ql.BlackConstantVol(self.settlement, self.calendar, self.vol, self.day_count)) self.bsm_process = ql.BlackScholesMertonProcess( self.spot_handle, self.dividend_yield, self.flat_ts, self.flat_vol_ts) binomial_engine = ql.BinomialVanillaEngine(self.bsm_process, "crr", self.steps) self.ql_option.setPricingEngine(binomial_engine) ql.BaroneAdesiWhaleyEngine(self.bsm_process)
def PricingFunc(self, option, process): '''------------- Set pricing engine, return both option and process -------------''' if self.exercise_type == 'E': engine = ql.AnalyticEuropeanEngine(process) elif self.exercise_type == 'A': engine = ql.BaroneAdesiWhaleyEngine(process) #engine = ql.BinomialVanillaEngine(process, "crr", 100) else: pass option.setPricingEngine(engine) return option.NPV()
def PricingFunc(self, option, process): '''设置定价引擎''' # 欧式、美式均为QuantLib.AnalyticBarrierEngine if self.product.exercise_type == 'E': engine = ql.AnalyticBarrierEngine(process) elif self.product.exercise_type == 'A': engine = ql.BaroneAdesiWhaleyEngine(process) else: pass option.setPricingEngine(engine) return option.NPV()
def PricingFunc(self, option, process): '''设置定价引擎,返回 option, process''' if self.product.exercise_type == 'E': engine = ql.AnalyticEuropeanEngine(process) elif self.product.exercise_type == 'A': engine = ql.BaroneAdesiWhaleyEngine(process) #engine = ql.BinomialVanillaEngine(process, "crr", 100) else: pass option.setPricingEngine(engine) return option.NPV()
def GreeksFunc(self, option, process): if self.product.exercise_type == 'E': engine = ql.AnalyticEuropeanEngine(process) option.setPricingEngine(engine) Greeks = pd.DataFrame([option.delta(),option.gamma(),option.vega()/100,option.theta()/365,option.rho()/100], columns = [''], \ index=['Delta','Gamma','Vega(%)','ThetaPerDay','Rho(%)']) elif self.product.exercise_type == 'A': #用离散法计算Greeks engine = ql.BaroneAdesiWhaleyEngine(process) #engine = ql.BinomialVanillaEngine(process, "crr", 100) #BTM option.setPricingEngine(engine) Greeks = self.Numerical_Greeks(option) #进入离散法计算Greeks else: pass return Greeks
def to_ql_option_engine(engine_name=None, process=None, model=None): """ Returns a QuantLib.PricingEngine for Options :param engine_name: str The engine name :param process: QuantLib.StochasticProcess The QuantLib object with the option Stochastic Process. :param model: QuantLib.CalibratedModel :return: QuantLib.PricingEngine """ if engine_name.upper() == 'BINOMIAL_VANILLA': return ql.BinomialVanillaEngine(process, 'LR', 801) elif engine_name.upper() == 'ANALYTIC_HESTON': if model is None: model = ql.HestonModel(process) elif model is not None and process is not None: model = model(process) return ql.AnalyticHestonEngine(model) elif engine_name.upper() == 'ANALYTIC_EUROPEAN': return ql.AnalyticEuropeanEngine(process) elif engine_name.upper() == 'ANALYTIC_EUROPEAN_DIVIDEND': return ql.AnalyticDividendEuropeanEngine(process) elif engine_name.upper() == "FINITE_DIFFERENCES": return ql.FdBlackScholesVanillaEngine(process) elif engine_name.upper() == 'HESTON_FINITE_DIFFERENCES': if model is None: model = ql.HestonModel(process) elif model is not None and process is not None: model = model(process) return ql.FdHestonVanillaEngine(model) elif engine_name.upper() == "BARONE_ADESI_WHALEY": return ql.BaroneAdesiWhaleyEngine(process) elif engine_name.upper() == "BJERKSUND_STENSLAND": return ql.BjerksundStenslandEngine(process) elif engine_name.upper() == "ANALYTIC_GJR_GARCH": if model is None: model = ql.GJRGARCHModel(process) elif model is not None and process is not None: model = model(process) return ql.AnalyticGJRGARCHEngine(model) elif engine_name.upper() == 'MC_GJR_GARCH': return ql.MCEuropeanGJRGARCHEngine(process=process, traits='pseudorandom', timeStepsPerYear=20, requiredTolerance=0.02) else: return None
# market data underlying = ql.SimpleQuote(36.0) volatilityQuote = ql.SimpleQuote(0.05) volatility = ql.BlackConstantVol(todaysDate, ql.QuoteHandle(volatilityQuote), ql.Actual365Fixed()) dividendYield = ql.FlatForward(settlementDate, 0.00, ql.Actual365Fixed()) # good to go process = ql.BlackScholesMertonProcess( ql.QuoteHandle(underlying), ql.YieldTermStructureHandle(dividendYield), ql.YieldTermStructureHandle(riskFreeRate), ql.BlackVolTermStructureHandle(volatility), ) option1 = ql.VanillaOption(process, payoff, exercise1) option1.setPricingEngine(ql.BaroneAdesiWhaleyEngine()) def f(x, y): underlying.setValue(x) volatilityQuote.setValue(y) return option1.NPV() def add_data(tvtk_data): """Add a TVTK data object `tvtk_data` to the mayavi pipleine. """ d = VTKDataSource() d.data = tvtk_data mayavi.add_source(d) return d
def get_option_greeks(**kwargs): # risk_free_rate and volatility in whole points not percentage points # for example enter 0.02 for 2 percent interest rate # enter 0.25 for 25 percent annual volatility underlying = kwargs['underlying'] strike = kwargs['strike'] risk_free_rate = kwargs['risk_free_rate'] expiration_date = kwargs['expiration_date'] calculation_date = kwargs['calculation_date'] option_type = kwargs['option_type'].upper() exercise_type = kwargs['exercise_type'].upper() dividend_rate = 0 expiration_datetime = cu.convert_doubledate_2datetime(expiration_date) calculation_datetime = cu.convert_doubledate_2datetime(calculation_date) expiration_date_obj = ql.Date(expiration_datetime.day, expiration_datetime.month, expiration_datetime.year) calculation_date_obj = ql.Date(calculation_datetime.day, calculation_datetime.month, calculation_datetime.year) cal_dte = day_count_obj.dayCount(calculation_date_obj, expiration_date_obj) nan_greeks = {'option_price': np.NaN, 'implied_vol': np.NaN, 'delta': np.NaN, 'vega': np.NaN, 'theta': np.NaN, 'cal_dte': cal_dte, 'gamma': np.NaN} if 'option_price' in kwargs.keys(): if option_type == 'C': if kwargs['option_price']+strike-underlying <= 10**(-12): nan_greeks['delta'] = 1 return nan_greeks elif option_type == 'P': if kwargs['option_price']-strike+underlying <= 10**(-12): nan_greeks['delta'] = -1 return nan_greeks if cal_dte == 0: if option_type == 'C': if strike <= underlying: nan_greeks['delta'] = 1 else: nan_greeks['delta'] = 0 elif option_type == 'P': if strike >= underlying: nan_greeks['delta'] = -1 else: nan_greeks['delta'] = 0 return nan_greeks if 'implied_vol' in kwargs.keys(): implied_vol = kwargs['implied_vol'] else: implied_vol = 0.15 if 'engine_name' in kwargs.keys(): engine_name = kwargs['engine_name'] else: engine_name = 'baw' if option_type == 'C': option_type_obj = ql.Option.Call elif option_type == 'P': option_type_obj = ql.Option.Put ql.Settings.instance().evaluationDate = calculation_date_obj if exercise_type == 'E': exercise_obj = ql.EuropeanExercise(expiration_date_obj) elif exercise_type == 'A': exercise_obj = ql.AmericanExercise(calculation_date_obj, expiration_date_obj) #print('years to expitation: ' + str(day_count_obj.yearFraction(calculation_date_obj, expiration_date_obj))) #print('spot: ' + str(underlying/m.exp(day_count_obj.yearFraction(calculation_date_obj, expiration_date_obj)*risk_free_rate))) #underlying_obj = ql.QuoteHandle(ql.SimpleQuote(underlying/m.exp(day_count_obj.yearFraction(calculation_date_obj, expiration_date_obj)*risk_free_rate))) underlying_obj = ql.QuoteHandle(ql.SimpleQuote(underlying)) flat_ts_obj = ql.YieldTermStructureHandle(ql.FlatForward(calculation_date_obj, risk_free_rate, day_count_obj)) dividend_yield_obj = ql.YieldTermStructureHandle(ql.FlatForward(calculation_date_obj, dividend_rate, day_count_obj)) flat_vol_ts_obj = ql.BlackVolTermStructureHandle(ql.BlackConstantVol(calculation_date_obj, calendar_obj, implied_vol, day_count_obj)) #bsm_process = ql.BlackScholesMertonProcess(underlying_obj, dividend_yield_obj, flat_ts_obj, flat_vol_ts_obj) bsm_process = ql.BlackProcess(underlying_obj, flat_ts_obj, flat_vol_ts_obj) payoff = ql.PlainVanillaPayoff(option_type_obj, strike) option_obj = ql.VanillaOption(payoff, exercise_obj) if (engine_name == 'baw')&(exercise_type == 'A'): option_obj.setPricingEngine(ql.BaroneAdesiWhaleyEngine(bsm_process)) elif (engine_name == 'fda')&(exercise_type == 'A'): option_obj.setPricingEngine(ql.FDAmericanEngine(bsm_process, 100, 100)) elif exercise_type == 'E': option_obj.setPricingEngine(ql.AnalyticEuropeanEngine(bsm_process)) option_price = option_obj.NPV() if 'option_price' in kwargs.keys(): try: implied_vol = option_obj.impliedVolatility(targetValue=kwargs['option_price'], process=bsm_process,accuracy=0.00001) flat_vol_ts_obj = ql.BlackVolTermStructureHandle(ql.BlackConstantVol(calculation_date_obj, calendar_obj, implied_vol, day_count_obj)) #bsm_process = ql.BlackScholesMertonProcess(underlying_obj, dividend_yield_obj, flat_ts_obj, flat_vol_ts_obj) bsm_process = ql.BlackProcess(underlying_obj, flat_ts_obj, flat_vol_ts_obj) if (engine_name == 'baw')&(exercise_type == 'A'): option_obj.setPricingEngine(ql.BaroneAdesiWhaleyEngine(bsm_process)) elif (engine_name == 'fda')&(exercise_type == 'A'): option_obj.setPricingEngine(ql.FDAmericanEngine(bsm_process, 100, 100)) elif exercise_type == 'E': option_obj.setPricingEngine(ql.AnalyticEuropeanEngine(bsm_process)) option_price = option_obj.NPV() except Exception: return nan_greeks option_obj = ql.VanillaOption(payoff, ql.EuropeanExercise(expiration_date_obj)) option_obj.setPricingEngine(ql.AnalyticEuropeanEngine(bsm_process)) return {'option_price': option_price, 'implied_vol': implied_vol, 'delta': option_obj.delta(), 'vega': option_obj.vega(), 'theta': option_obj.thetaPerDay(), 'cal_dte': cal_dte, 'gamma': option_obj.gamma()}
# Option Process process = ql.BlackScholesMertonProcess( ql.QuoteHandle(S), ql.YieldTermStructureHandle(q), ql.YieldTermStructureHandle(r), ql.BlackVolTermStructureHandle(v), ) option = ql.VanillaOption(payoff, exercise) refValue = $reference value$ report("reference value", refValue) # method - analytic option.setPricingEngine(ql.BaroneAdesiWhaleyEngine(process)) report("Barone-Adesi-Whaley", option.NPV()) option.setPricingEngine(ql.BjerksundStenslandEngine(process)) report("Bjerksund-Stensland", option.NPV()) # method - finite differences timeSteps = 801 gridPoints = 800 option.setPricingEngine(ql.FDAmericanEngine(process, timeSteps, gridPoints)) report("finite differences", option.NPV()) # method - binomial timeSteps = 801