def plainvanilla(today, s, k, r, q, matDate, vol, flag): ql.Settings.instance().evaluationDate = ql.Date(today.day, today.month, today.year) riskFreeRate = ql.FlatForward(today, r, ql.Actual365Fixed()) # option parameters exercise = ql.EuropeanExercise(matDate) if (flag.lower() == "c" or flag.lower() == "call"): optionType = ql.Option.Call else: optionType = ql.Option.Put payoff = ql.PlainVanillaPayoff(optionType, k) underlying = ql.SimpleQuote(s) volatility = ql.BlackConstantVol(today, ql.SouthKorea(), vol, ql.Actual365Fixed()) dividendYield = ql.FlatForward(today, q, ql.Actual365Fixed()) process = ql.BlackScholesMertonProcess( ql.QuoteHandle(underlying), ql.YieldTermStructureHandle(dividendYield), ql.YieldTermStructureHandle(riskFreeRate), ql.BlackVolTermStructureHandle(volatility)) option = ql.VanillaOption(payoff, exercise) # method: analytic option.setPricingEngine(ql.AnalyticEuropeanEngine(process)) res = { "npv": option.NPV(), "delta": option.delta() * 0.01 * s, "gamma": option.gamma() * ((0.01 * s)**2), "theta": option.theta() } return res
def bondOptionDetails(self): # calculate expiryTime, (coupon) startTims, payTimes, cashFlows, strike and # c/p flag as inputs to Hull White analytic formula details = {} details['callOrPut'] = 1.0 if self.underlyingSwap.payerOrReceiver==ql.VanillaSwap.Receiver else -1.0 details['strike'] = 0.0 refDate = self.underlyingSwap.discHandle.referenceDate() details['expiryTime'] = ql.Actual365Fixed().yearFraction(refDate,self.exercise.dates()[0]) fixedLeg = [ [ ql.Actual365Fixed().yearFraction(refDate,cf.date()), cf.amount() ] for cf in self.underlyingSwap.swap.fixedLeg() ] details['fixedLeg'] = np.array(fixedLeg) floatLeg = [ [ ql.Actual365Fixed().yearFraction(refDate,ql.as_coupon(cf).accrualStartDate()), ((1 + ql.as_coupon(cf).accrualPeriod()*ql.as_coupon(cf).rate()) * self.underlyingSwap.discHandle.discount(ql.as_coupon(cf).accrualEndDate()) / self.underlyingSwap.discHandle.discount(ql.as_coupon(cf).accrualStartDate()) - 1.0) * ql.as_coupon(cf).nominal() ] for cf in self.underlyingSwap.swap.floatingLeg() ] details['floatLeg'] = np.array(floatLeg) payTimes = [ floatLeg[0][0] ] + \ [ cf[0] for cf in floatLeg ] + \ [ cf[0] for cf in fixedLeg ] + \ [ ql.Actual365Fixed().yearFraction(refDate,ql.as_coupon( self.underlyingSwap.swap.floatingLeg()[-1]).accrualEndDate()) ] caschflows = [ -ql.as_coupon(self.underlyingSwap.swap.floatingLeg()[0]).nominal() ] + \ [ -cf[1] for cf in floatLeg ] + \ [ cf[1] for cf in fixedLeg ] + \ [ ql.as_coupon(self.underlyingSwap.swap.floatingLeg()[0]).nominal() ] details['payTimes' ] = np.array(payTimes) details['cashFlows'] = np.array(caschflows) return details
def makeSwaption(self, vol, volType=ql.ShiftedLognormal, delivery=ql.Settlement.Physical, settlementMethod=ql.Settlement.PhysicalOTC, shift=0.02, swapRebuild=True): if swapRebuild: self.makeSwap(self.optionTenor, self.swapTenor, self.fairRate) self.volHandle = ql.QuoteHandle(ql.SimpleQuote(vol)) self.payerSwaption = ql.Swaption( self.payerSwap, ql.EuropeanExercise(self.exerciseDate), delivery, settlementMethod) self.receiverSwaption = ql.Swaption( self.receiverSwap, ql.EuropeanExercise(self.exerciseDate), delivery, settlementMethod) if volType == ql.ShiftedLognormal: swaptionEngine = ql.BlackSwaptionEngine( self.discountTermStructure, ql.QuoteHandle(ql.SimpleQuote(vol)), ql.Actual365Fixed(), shift) elif volType == ql.Normal: swaptionEngine = ql.BachelierSwaptionEngine( self.discountTermStructure, ql.QuoteHandle(ql.SimpleQuote(vol)), ql.Actual365Fixed()) self.payerSwaption.setPricingEngine(swaptionEngine) self.receiverSwaption.setPricingEngine(swaptionEngine)
def ql_irr(cash_flow, first_amount, first_date): """ Calculate the IRR from a given cash flow :param cash_flow: list List of QuantLib.SimpleCashFlow (s) :param first_amount: Int The Amount of the first cash flow :param first_date: Date-Like The date of the first cash flow :return: float """ ql.Settings.instance().evaluationDate = to_ql_date(first_date) try: fixed_rate = ql.CashFlows.yieldRate(cash_flow, float(first_amount), ql.Actual365Fixed(), ql.Compounded, ql.Annual, False, ql.Date(), ql.Date(), 1.0e-6, 1000, 0.05) except RuntimeError: try: fixed_rate = ql.CashFlows.yieldRate(cash_flow, float(first_amount), ql.Actual365Fixed(), ql.Compounded, ql.Annual, False, ql.Date(), ql.Date(), 1.0e-6, 1000, -0.1) except RuntimeError: fixed_rate = ql.CashFlows.yieldRate(cash_flow, float(first_amount), ql.Actual365Fixed(), ql.Compounded, ql.Annual, False, ql.Date(), ql.Date(), 1.0e-6, 1000, -0.5) return fixed_rate
def setUp(self): self.calendar = ql.TARGET() self.today = self.calendar.adjust(ql.Date.todaysDate()) ql.Settings.instance().evaluationDate = self.today projection_curve_handle = ql.RelinkableYieldTermStructureHandle() self.projection_rate = 0.01 self.projection_quote_handle = ql.RelinkableQuoteHandle() projection_curve = ql.FlatForward( self.today, self.projection_quote_handle, ql.Actual365Fixed()) projection_curve_handle.linkTo(projection_curve) self.discount_handle = ql.YieldTermStructureHandle(ql.FlatForward( self.today, ql.QuoteHandle(ql.SimpleQuote(0.0085)), ql.Actual365Fixed())) self.swap_engine = ql.DiscountingSwapEngine(self.discount_handle) self.idx = ql.Euribor6M(projection_curve_handle) self.exercises = [ql.Period(1, ql.Years), ql.Period(2, ql.Years), ql.Period(3, ql.Years), ql.Period(5, ql.Years), ql.Period(7, ql.Years), ql.Period(10, ql.Years)] self.lengths = [ql.Period(1, ql.Years), ql.Period(2, ql.Years), ql.Period(3, ql.Years), ql.Period(5, ql.Years), ql.Period(7, ql.Years), ql.Period(10, ql.Years), ql.Period(15, ql.Years), ql.Period(20, ql.Years)] self.swap_type = [ql.VanillaSwap.Receiver, ql.VanillaSwap.Payer]
def setUp(self): # we set up a QuantLib VanillaSwap as basic test object today = ql.Date(5,ql.October,2020) ql.Settings.instance().evaluationDate = today # we need curves for the float leg discYtsH = ql.YieldTermStructureHandle( ql.FlatForward(today,0.01,ql.Actual365Fixed())) projYtsH = ql.YieldTermStructureHandle( ql.FlatForward(today,0.02,ql.Actual365Fixed())) index = ql.Euribor6M(projYtsH) # we set start in the future to avoid the need of index fixings startDate = ql.Date(12,ql.October,2020) endDate = ql.Date(12,ql.October,2030) calendar = ql.TARGET() fixedTenor = ql.Period('1y') floatTenor = ql.Period('6m') fixedSchedule = ql.MakeSchedule(startDate,endDate,tenor=fixedTenor,calendar=calendar) floatSchedule = ql.MakeSchedule(startDate,endDate,tenor=floatTenor,calendar=calendar) swapType = ql.VanillaSwap.Payer vanillaSwap = ql.VanillaSwap(ql.VanillaSwap.Receiver,1.0,fixedSchedule,0.025,ql.Thirty360(),floatSchedule,index,0.0050,ql.Actual360()) # we have all the incredients to price the swap - but not really needed for payoffs engine = ql.DiscountingSwapEngine(discYtsH) vanillaSwap.setPricingEngine(engine) # It is easier to work with legs instead of Swap intruments self.legs = [vanillaSwap.fixedLeg(), vanillaSwap.floatingLeg()] self.pors = [1.0, -1.0] if swapType==ql.VanillaSwap.Receiver else [-1.0, 1.0] self.discYtsH = discYtsH
def swaptionDetails(self): # calculate times and cash flows as input to (cash-settled) swaption valuation details = {} details[ 'callOrPut'] = 1.0 if self.underlyingSwap.payerOrReceiver == ql.VanillaSwap.Receiver else -1.0 details['strikeRate'] = self.underlyingSwap.fixedRate details['notional'] = self.underlyingSwap.notional refDate = self.underlyingSwap.discHandle.referenceDate() details['expiryTime'] = ql.Actual365Fixed().yearFraction( refDate, self.exercise.dates()[0]) annuityLeg = [[ ql.Actual365Fixed().yearFraction(refDate, cf.date()), ql.as_coupon(cf).accrualPeriod() ] for cf in self.underlyingSwap.swap.fixedLeg()] details['annuityLeg'] = np.array(annuityLeg) floatLeg = [[ ql.Actual365Fixed().yearFraction( refDate, ql.as_coupon(cf).accrualStartDate()), ((1 + ql.as_coupon(cf).accrualPeriod() * ql.as_coupon(cf).rate()) * self.underlyingSwap.discHandle.discount( ql.as_coupon(cf).accrualEndDate()) / self.underlyingSwap.discHandle.discount( ql.as_coupon(cf).accrualStartDate()) - 1.0) ] for cf in self.underlyingSwap.swap.floatingLeg()] floatLeg = floatLeg + [[ floatLeg[0][0], 1.0 ]] + \ [[ ql.Actual365Fixed().yearFraction(refDate,ql.as_coupon( self.underlyingSwap.swap.floatingLeg()[-1]).accrualEndDate()), -1.0 ]] details['floatLeg'] = np.array(floatLeg) return details
def setUp(self): self.todaysDate = ql.Date(5, ql.September, 2017) ql.Settings.instance().evaluationDate = self.todaysDate self.spotDate = ql.Date(7, ql.September, 2017) self.domestic_rate = ql.FlatForward(self.spotDate, 0.017, ql.Actual365Fixed()) self.foreign_rate = ql.FlatForward(self.spotDate, 0.013, ql.Actual365Fixed())
def npvRaw(self): # calculate npv manually using Bachelier formula # use this to cross-check npv calculation via QuantLib engine refDate = self.underlyingSwap.discHandle.referenceDate() T = ql.Actual365Fixed().yearFraction(refDate,self.exercise.dates()[0]) CallOrPutOnS = 1.0 if self.underlyingSwap.payerOrReceiver==ql.VanillaSwap.Payer else -1.0 return self.annuity() * Bachelier(self.underlyingSwap.fixedRate,self.fairRate(),self.normalVolatility,T,CallOrPutOnS)
def testOrnsteinUhlenbeckVsBachelier(self): """Testing Fdm Ornstein-Uhlenbeck pricing""" todaysDate = ql.Date(15, ql.January, 2020) ql.Settings.instance().evaluationDate = todaysDate dc = ql.Actual365Fixed() rTS = ql.FlatForward(todaysDate, 0.06, dc) strike = 110.0 payoff = ql.PlainVanillaPayoff(ql.Option.Put, strike) maturityDate = todaysDate + ql.Period(2, ql.Years) exercise = ql.EuropeanExercise(maturityDate) option = ql.VanillaOption(payoff, exercise) x0 = 100 sigma = 20.0 speed = 5 pdeEngine = ql.FdOrnsteinUhlenbeckVanillaEngine( ql.OrnsteinUhlenbeckProcess(speed, sigma, x0, x0), rTS, 50) option.setPricingEngine(pdeEngine) calculated = option.NPV() stdev = math.sqrt(sigma * sigma / (2 * speed)) expected = ql.bachelierBlackFormula(ql.Option.Put, strike, x0, stdev, rTS.discount(maturityDate)) self.assertAlmostEqual(calculated, expected, 2)
def jpy_3m_example(): calendar = objects.get('JAPAN') start = ql.Date(15, 3, 2020) maturity = ql.Date(15, 6, 2020) fixedSchedule = ql.MakeSchedule(start, maturity, ql.Period('3M'), calendar=calendar) floatSchedule = ql.MakeSchedule(start, maturity, ql.Period('3M'), calendar=calendar) jpy_3m_crv = curves.get('JPY.3M') jpy_3m_yts = ql.YieldTermStructureHandle(jpy_3m_crv) jpy_libor_3m = objects.get('JPY.3M').clone(jpy_3m_yts) jpy_yts = ql.YieldTermStructureHandle(curves.get('JPY.OIS')) engine = ql.DiscountingSwapEngine(jpy_yts) swap = ql.VanillaSwap(ql.VanillaSwap.Receiver, 1e9, fixedSchedule, -0.15 / 100, ql.Actual365Fixed(), floatSchedule, jpy_libor_3m, 0, ql.Actual360()) swap.setPricingEngine(engine) print(f"Swap NPV : {swap.NPV():,.2f}") print(f"Swap Rate : {swap.fairRate() * 100:,.6f}")
def vega(self): refDate = self.underlyingSwap.discHandle.referenceDate() T = ql.Actual365Fixed().yearFraction(refDate, self.exercise.dates()[0]) return (self.annuity() * BachelierVega(self.underlyingSwap.fixedRate, self.fairRate(), self.normalVolatility, T) * 1.0e-4 ) # 1bp scaling
def testBSMRNDCalculator(self): """Testing Black-Scholes risk neutral density calculator""" dc = ql.Actual365Fixed() todaysDate = ql.Date(15, ql.January, 2020) r = 0.0 q = 0.0 vol = 0.2 s0 = 100 process = ql.BlackScholesMertonProcess( ql.QuoteHandle(ql.SimpleQuote(s0)), ql.YieldTermStructureHandle(ql.FlatForward(todaysDate, q, dc)), ql.YieldTermStructureHandle(ql.FlatForward(todaysDate, r, dc)), ql.BlackVolTermStructureHandle( ql.BlackConstantVol(todaysDate, ql.TARGET(), vol, dc))) rnd = ql.BSMRNDCalculator(process) t = 1.2 x = math.log(80.0) mu = math.log(s0) + (r - q - 0.5 * vol * vol) * t calculated = rnd.pdf(x, t) stdev = vol * math.sqrt(t) expected = (1.0 / (math.sqrt(2 * math.pi) * stdev) * math.exp(-0.5 * math.pow((x - mu) / stdev, 2.0))) self.assertAlmostEqual(calculated, expected, 8)
def __init__( self, forward_rate: float, atm_forward_volatility: float, beta: float, nu: float, rho: float, reference_date: ql.Date, maturity_date: ql.Date, shift: float = 0.0, day_counter: ql.DayCounter = ql.Actual365Fixed() ) -> None: self.shift = shift if self.shift < 0.0: raise ValueError('Shift must be non-negative') self.shifted_forward_rate = forward_rate + self.shift if self.shifted_forward_rate < 0.0: raise ValueError('Shifted forward rate cannot be negative') self.atm_forward_volatility = atm_forward_volatility self.reference_date = reference_date self.maturity_date = maturity_date self.day_counter = day_counter self.time_to_maturity = self.compute_time_to_maturity() self.beta = beta self.nu = nu self.rho = rho self.alpha = self.update_alpha()
def set_values(self,request_form): spot_rate = float(request_form['spotprice']) strike_rate = float(request_form['strikeprice']) domestic_interest_rate = float(request_form['domesticInterestrate']) foreign_interest_rate = float(request_form['foreignInterestrate']) volatility = float(request_form['volatility']) expiration_date = ql.Date(int(request_form['expirationdate'][8:10]),int(request_form['expirationdate'][5:7]),int(request_form['expirationdate'][0:4])) start_date = ql.Date(int(request_form['startdate'][8:10]),int(request_form['startdate'][5:7]),int(request_form['startdate'][0:4])) settlement_date = start_date days = ql.Actual365Fixed() calendar = ql.Japan() frequency = ql.Annual ql.Settings.instance().evaluationDate = start_date if(request_form['callput'] == 'call'): option_type = ql.Option.Call else: option_type = ql.Option.Put compounding = ql.Compounded payoff = ql.PlainVanillaPayoff(option_type, strike_rate) eu_exercise = ql.EuropeanExercise(expiration_date) european_option = ql.VanillaOption(payoff, eu_exercise) spot_handle = ql.QuoteHandle(ql.SimpleQuote(spot_rate)) rTS = ql.YieldTermStructureHandle(ql.FlatForward(settlement_date,domestic_interest_rate, days,compounding, frequency)) fTS = ql.YieldTermStructureHandle(ql.FlatForward(settlement_date,foreign_interest_rate, days,compounding, frequency)) flat_vol_ts = ql.BlackVolTermStructureHandle(ql.BlackConstantVol(settlement_date, calendar, volatility, days)) garman_kohlagen_process = ql.GarmanKohlagenProcess(spot_handle, fTS, rTS, flat_vol_ts) engine = ql.AnalyticEuropeanEngine(garman_kohlagen_process) european_option.setPricingEngine(engine); return float(european_option.NPV()),float(european_option.delta())
def setUp(self): ql.Settings.instance().evaluationDate = ql.Date(26, 5, 2021) self.basis_point = 1.0e-4 self.settlement_days = 2 self.business_day_convention = ql.Following self.calendar = ql.TARGET() self.day_count = ql.Actual365Fixed() self.end_of_month = False base_ccy_idx_handle = ql.YieldTermStructureHandle(flat_rate(0.007)) quoted_ccy_idx_handle = ql.YieldTermStructureHandle(flat_rate(0.015)) self.base_ccy_idx = ql.Euribor3M(base_ccy_idx_handle) self.quote_ccy_idx = ql.USDLibor( ql.Period(3, ql.Months), quoted_ccy_idx_handle) self.collateral_ccy_handle = ql.YieldTermStructureHandle( flat_rate(0.009)) # Cross currency basis swaps data source: # N. Moreni, A. Pallavicini (2015) # FX Modelling in Collateralized Markets: foreign measures, basis curves # and pricing formulae. # section 4.2.1, Table 2. self.cross_currency_basis_quotes = ((ql.Period(1, ql.Years), -14.5), (ql.Period(18, ql.Months), -18.5), (ql.Period(2, ql.Years), -20.5), (ql.Period(3, ql.Years), -23.75), (ql.Period(4, ql.Years), -25.5), (ql.Period(5, ql.Years), -26.5), (ql.Period(7, ql.Years), -26.75), (ql.Period(10, ql.Years), -26.25), (ql.Period(15, ql.Years), -24.75), (ql.Period(20, ql.Years), -23.25), (ql.Period(30, ql.Years), -20.50))
def build_nominal_term_structure( reference_date, nominal_data): nominal_dc = ql.Actual365Fixed() dates = [CAL.advance(reference_date, x[0]) for x in nominal_data] rates = [x[1] for x in nominal_data] return ql.ZeroCurve(dates, rates, nominal_dc)
def getQLZeroCurve(self): #dates1=[ql.Date(i.serialNumber()) for i in dates] #zeros1=deepcopy(zeros) x1 = [i.serialNumber() for i in self.tenordates] y1 = self.zerorates x2 = [i.serialNumber() for i in self.basecurve.tenordates] y2 = self.basecurve.zerorates datesS = x1 + list(set(x2) - set(x1)) # get all unique dates datesS.sort() dates1 = [] for i in range(0, len(datesS)): dates1.append(ql.Date(datesS[i])) if self.nullbeforefirstpillar: zeros1 = np.interp(datesS, x1, y1, left=0.0, right=y1[-1]) \ + np.interp(datesS, x2, y2, left=y2[0], right=y2[-1]) else: zeros1 = np.interp(datesS, x1, y1, left=y1[0], right=y1[-1]) \ + np.interp(datesS, x2, y2, left=y2[0], right=y2[-1]) dates1.insert(0, self.valuationdate) zeros1 = zeros1.tolist() zeros1.insert(0, zeros1[0]) calendar = ql.WeekendsOnly() dates1.append(calendar.advance(dates1[-1], 1, ql.Years)) zeros1.append(zeros1[-1]) # to do change us holiday? return ql.ZeroCurve(dates1, zeros1, ql.Actual365Fixed(), ql.UnitedStates(), ql.Linear(), ql.Continuous)
def binomialmodels(stockprice, strikeprice, volatility, intrate, calcdate, expdate, divrate, opttype, modelname, steps): day_count = ql.Actual365Fixed() calendar = ql.UnitedStates() calculation_date = ql.Date(calcdate.day, calcdate.month, calcdate.year) if opttype == "p": option_type = ql.Option.Put else: option_type = ql.Option.Call exp_date = ql.Date(expdate.day, expdate.month, expdate.year) ql.Settings.instance().evaluationDate = calculation_date payoff = ql.PlainVanillaPayoff(option_type, strikeprice) exercise = ql.AmericanExercise(calculation_date, exp_date) american_option = ql.VanillaOption(payoff, exercise) spot_handle = ql.QuoteHandle(ql.SimpleQuote(stockprice)) flat_ts = ql.YieldTermStructureHandle( ql.FlatForward(calculation_date, intrate, day_count)) dividend_yield = ql.YieldTermStructureHandle( ql.FlatForward(calculation_date, divrate, day_count)) flat_vol_ts = ql.BlackVolTermStructureHandle( ql.BlackConstantVol(calculation_date, calendar, volatility, day_count)) bsm_process = ql.BlackScholesMertonProcess(spot_handle, dividend_yield, flat_ts, flat_vol_ts) binomial_engine = ql.BinomialVanillaEngine(bsm_process, modelname, steps) american_option.setPricingEngine(binomial_engine) return american_option.NPV()
def __call__(self, date, csv_path, yts_handle_ois): yts_handle = ql.RelinkableYieldTermStructureHandle() cv_df = pd.read_csv(csv_path, index_col='Term') cv = cv_df.drop( columns=['Shift', 'Shifted Rate', 'Zero Rate', 'Discount']) cv['Market Rate'] = cv_df['Market Rate'] * 0.01 helpers = ql.RateHelperVector() index_libor = ql.USDLibor(ql.Period('3m'), yts_handle) simple_quote = [] for term, data in cv.iterrows(): term = term.replace(' ', '') if term == '3MO': simple_quote.append(ql.SimpleQuote(float(data['Market Rate']))) helpers.append( ql.DepositRateHelper(ql.QuoteHandle(simple_quote[-1]), index_libor)) elif term[:2] == 'ED': simple_quote.append( ql.SimpleQuote((1.0 - float(data['Market Rate'])) * 100)) helpers.append( ql.FuturesRateHelper(ql.QuoteHandle(simple_quote[-1]), ql.IMM.date(term[-2:]), index_libor)) elif term[-2:] == 'YR': simple_quote.append(ql.SimpleQuote(float(data['Market Rate']))) swapIndex = ql.UsdLiborSwapIsdaFixAm( ql.Period(term.replace('YR', 'y'))) helpers.append( ql.SwapRateHelper(ql.QuoteHandle(simple_quote[-1]), swapIndex, ql.QuoteHandle(), ql.Period(), yts_handle_ois)) return ql.PiecewiseLogLinearDiscount(date, helpers, ql.Actual365Fixed())
def setUp(self): self.today = ql.Date(21, ql.April, 2019) self.dc = ql.Actual365Fixed() ql.Settings.instance().evaluationDate = self.today self.domesticTS = ql.FlatForward(self.today, 0.025, self.dc) self.foreignTS = ql.FlatForward(self.today, 0.075, self.dc) self.fxVolTS = ql.BlackConstantVol(self.today, ql.TARGET(), 0.15, self.dc) self.quantoHelper = ql.FdmQuantoHelper( self.domesticTS, self.foreignTS, self.fxVolTS, -0.75, 1.0) self.divYieldTS = ql.FlatForward(self.today, 0.03, self.dc) divDate = ql.DateVector() divDate.push_back(self.today + ql.Period(6, ql.Months)) divAmount = ql.DoubleVector() divAmount.push_back(8.0) maturityDate = self.today + ql.Period(9, ql.Months) self.option = ql.DividendVanillaOption( ql.PlainVanillaPayoff(ql.Option.Call, 105), ql.AmericanExercise(self.today, maturityDate), divDate, divAmount)
def day_count_fraction(self, dcf): """ day_count_fraction takes a string that is used in the conventions DataFrame, and returns the QuantLib-equivalent day-count object. This function takes all day-counters that are currently allowed in QuantLib. Currently, the function takes the following strings: Act360, Act365Fixed, ActAct, Bus252, 30360 Args: dcf (str): day count fraction string Returns: object: QuantLib day-count-fraction object """ if dcf == 'Act360': return qlib.Actual360() elif dcf == 'Act365Fixed': return qlib.Actual365Fixed() elif dcf == 'ActAct': return qlib.ActualActual() elif dcf == 'Bus252': return qlib.Business252() elif dcf == '30360': return qlib.Thirty360()
def testPdeSolver(self): """ Testing BENCHOP-SLV SABR example value """ today = ql.Date(8, 1, 2019) dc = ql.Actual365Fixed() maturityDate = today + ql.Period(10 * 365, ql.Days) maturityTime = dc.yearFraction(today, maturityDate) f0 = 0.07 alpha = 0.4 nu = 0.8 beta = 0.5 rho = -0.6 strike = f0 * math.exp(-0.1 * math.sqrt(maturityTime)) rTS = ql.YieldTermStructureHandle(ql.FlatForward(today, 0.0, dc)) # see https://ir.cwi.nl/pub/28249 expected = 0.052450313614407 option = ql.VanillaOption( ql.PlainVanillaPayoff(ql.Option.Call, strike), ql.EuropeanExercise(maturityDate)) option.setPricingEngine( ql.FdSabrVanillaEngine(f0, alpha, beta, nu, rho, rTS, 30, 800, 30, 1, 0.8)) calculated = option.NPV() self.assertAlmostEqual( calculated, expected, 4, msg="Unable to reproduce Le Floc'h-Kennedy SABR volalatility")
def testHagenFormula(self): """ Testing Hagen et al. formula """ today = ql.Date(9, 1, 2019) dc = ql.Actual365Fixed() maturityDate = today + ql.Period(6, ql.Months) maturityTime = dc.yearFraction(today, maturityDate) alpha = 0.35 beta = 0.85 nu = 0.75 rho = 0.85 f0 = 100.0 strike = 110.0 sabrVol = ql.sabrVolatility(strike, f0, maturityTime, alpha, beta, nu, rho) self.assertAlmostEqual( sabrVol, 0.205953, 6, msg="Unable to reproduce Hagen et al. SABR volalatility") flochKennedyVol = ql.sabrFlochKennedyVolatility( strike, f0, maturityTime, alpha, beta, nu, rho) self.assertAlmostEqual( flochKennedyVol, 0.205447, 6, msg="Unable to reproduce Le Floc'h-Kennedy SABR volalatility")
def call_price_exact(kappa, theta, beta, rho, v0, r, T, s0, K): strike_price = 110.0 payoff = ql.PlainVanillaPayoff(ql.Option.Call, strike_price) # option data calculation_date = ql.Date(15, 1, 2011) maturity_date = ql.Date(15, 1, 2011 + T) spot_price = s0 strike_price = K dividend_rate = 0.00 option_type = ql.Option.Call risk_free_rate = r day_count = ql.Actual365Fixed() ql.Settings.instance().evaluationDate = calculation_date # construct the Heston process payoff = ql.PlainVanillaPayoff(option_type, strike_price) exercise = ql.EuropeanExercise(maturity_date) european_option = ql.VanillaOption(payoff, exercise) sigma = beta spot_handle = ql.QuoteHandle(ql.SimpleQuote(spot_price)) flat_ts = ql.YieldTermStructureHandle( ql.FlatForward(calculation_date, risk_free_rate, day_count)) dividend_yield = ql.YieldTermStructureHandle( ql.FlatForward(calculation_date, dividend_rate, day_count)) heston_process = ql.HestonProcess(flat_ts, dividend_yield, spot_handle, v0, kappa, theta, sigma, rho) engine = ql.AnalyticHestonEngine(ql.HestonModel(heston_process), 0.0000001, 100000) european_option.setPricingEngine(engine) h_price = european_option.NPV() return h_price
def set_up_option(maturity_date, spot_price, strike_price, volatility, risk_free_rate, calculation_date): # assume no dividend dividend_rate = 0.0 option_type = ql.Option.Call day_count = ql.Actual365Fixed() calendar = ql.UnitedStates() ql.Settings.instance().evaluationDate = calculation_date # construct the European Option payoff = ql.PlainVanillaPayoff(option_type, strike_price) exercise = ql.EuropeanExercise(maturity_date) european_option = ql.VanillaOption(payoff, exercise) spot_handle = ql.QuoteHandle(ql.SimpleQuote(spot_price)) flat_ts = ql.YieldTermStructureHandle( ql.FlatForward(calculation_date, risk_free_rate, day_count)) dividend_yield = ql.YieldTermStructureHandle( ql.FlatForward(calculation_date, dividend_rate, day_count)) flat_vol_ts = ql.BlackVolTermStructureHandle( ql.BlackConstantVol(calculation_date, calendar, volatility, day_count)) bsm_process = ql.BlackScholesMertonProcess(spot_handle, dividend_yield, flat_ts, flat_vol_ts) bsm_process.option = european_option return bsm_process
def to_ql_day_counter(arg): """Converts a string with day_counter name to the corresponding QuantLib object. Parameters ---------- arg: str Returns ------- QuantLib.DayCounter """ if arg.upper() == "THIRTY360E": return ql.Thirty360(ql.Thirty360.European) elif arg.upper() == "THIRTY360": return ql.Thirty360() elif arg.upper() == "ACTUAL360": return ql.Actual360() elif arg.upper() == "ACTUAL365": return ql.Actual365Fixed() elif arg.upper() == "ACTUALACTUAL": return ql.ActualActual(ql.ActualActual.ISMA) elif arg.upper() == "ACTUALACTUALISMA": return ql.ActualActual(ql.ActualActual.ISMA) elif arg.upper() == "ACTUALACTUALISDA": return ql.ActualActual(ql.ActualActual.ISDA) elif arg.upper() == "BUSINESS252": return ql.Business252() else: raise ValueError( "Unable to convert {} to a QuantLib day counter".format(arg))
def get_vanilla_option_price_sabr(self, strike, maturity_period, use_noarbsabr=False, option_type=ql.Option.Call): self.option = self.vanilla_option_helper(strike, maturity_period, option_type) maturity = ql.Actual365Fixed().yearFraction( self.base_date, self.calendar.advance(self.base_date, maturity_period)) if use_noarbsabr: sabr_vol = ql.sabrFlochKennedyVolatility( strike, self.handles['initS'].value(), maturity, self.handles['alpha'].value(), self.handles['beta'].value(), self.handles['nu'].value(), self.handles['rho'].value()) else: sabr_vol = ql.sabrVolatility(strike, self.handles['initS'].value(), maturity, self.handles['alpha'].value(), self.handles['beta'].value(), self.handles['nu'].value(), self.handles['rho'].value()) npv = ql.blackFormula( option_type, strike, self.handles['initS'].value(), sabr_vol * sqrt(maturity), exp(-self.handles['risk_free_rate'].value() * maturity)) return npv
def __init__(self, tradeDate=FLAGS.TODAY, maturity_date=FLAGS.MATURITY, spot_price=FLAGS.SPOT, process_parameters={ 'drift': FLAGS.BS_DRIFT, 'sigma': FLAGS.BS_SIGMA }, n_paths=FLAGS.SMALL_SAMPLE): """__init__. :param tradeDate: :param maturity_date: :param spot_price: :param process_parameters: :param n_paths: """ self.tradeDate = tradeDate self.maturity_date = maturity_date self.spot_price = spot_price self.process_parameters = process_parameters self.n_paths = n_paths self.dates = scheduler(self.tradeDate, self.maturity_date) self._check() day_count = ql.Actual365Fixed() self.maturity = day_count.yearFraction(self.tradeDate, self.maturity_date)
def get_shanghai_repo_1m(date): calc_date = str_date_2_ql_date(date) ql.Settings.instance().evaluationDate = calc_date calendar = ql.China() bussiness_convention = ql.Following dayCount = ql.Actual365Fixed() end_of_month = False # 设置回购的基本信息 w.start() # 获取上交所1d,2d,7d,14d,28d回购的数据,只取一个月期限内流动性好的品种 repo_maturities = [ ql.Period(1, ql.Days), ql.Period(2, ql.Days), ql.Period(7, ql.Days), ql.Period(14, ql.Days), ql.Period(28, ql.Days) ] repo_rates = w.wss( "204001.SH,204002.SH,204003.SH,204004.SH,204007.SH,204014.SH,204028.SH,204091.SH", "close", "tradeDate=20190121;priceAdj=U;cycle=D").Data[0] repo_rate_helpers = [] for i, repo_maturity in enumerate(repo_maturities): repo_rate_helpers.append( ql.DepositRateHelper( ql.QuoteHandle(ql.SimpleQuote(repo_rates[i] / 100.0)), repo_maturity, 0, calendar, bussiness_convention, end_of_month, dayCount)) return repo_rate_helpers