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 test_convert_daycount(self): keys = QuantLibConverter._daycount_map.keys() vals = QuantLibConverter._daycount_map.values() for key, val in QuantLibConverter._daycount_map.iteritems(): dc = QuantLibConverter.to_daycount(key) self.assertTrue(dc == val) dc = QuantLibConverter.to_daycount(val) self.assertTrue(dc == val) dc_choices = [ "ACT/ACT", "ACT/ACT (BOND)", "30/360", "ACT/365", "Actual/365 (Fixed)", "NL/365" ] dc_values = [ ql.ActualActual(), ql.ActualActual(ql.ActualActual.Bond), ql.Thirty360(), ql.ActualActual(), ql.Actual365Fixed(), ql.Actual365NoLeap() ] for dc_choice, dc_value in zip(dc_choices, dc_values): dc = QuantLibConverter.to_daycount(dc_choice) self.assertTrue(dc == dc_value)
def __init__(self, cd_frequency, df_option_metrics, hp, min_ttm=2, col_date='dt_date', col_datetime='dt_datetime', pricing_type='OptionPlainEuropean', engine_type='AnalyticEuropeanEngine'): self.util = BktUtil() self.frequency = cd_frequency self.df_metrics = df_option_metrics self.pricing_type = pricing_type self.engine_type = engine_type self.hp = hp self.min_ttm = min_ttm self.daycounter = ql.ActualActual() self.calendar = ql.China() self.bktoption_list = [] self.bktoption_list_call = [] self.bktoption_list_put = [] self.eligible_maturities = [] self.index = 0 self.update_multiplier_adjustment() self.start()
def __init__(self, cd_frequency, df_daily_metrics, df_intraday_metrics=None, id_instrument='', pricing_type='OptionPlainEuropean', engine_type='AnalyticEuropeanEngine'): self.util = BktUtil() self.frequency = cd_frequency self.id_instrument = id_instrument self.df_daily_metrics = df_daily_metrics # Sorted ascending by date/datetime if self.frequency in self.util.cd_frequency_low: self.df_metrics = df_daily_metrics else: self.df_metrics = df_intraday_metrics self.start_index = 0 self.nbr_index = len(df_daily_metrics) self.last_index = len(df_daily_metrics) - 1 self.dt_list = sorted(self.df_metrics[self.util.col_date].unique()) self.pricing_type = pricing_type self.engine_type = engine_type self.implied_vol = None self.trade_unit = 0 self.daycounter = ql.ActualActual() self.calendar = ql.China() self.start()
def ZERO_RATE(date, curve): date = ql.Date(date.day, date.month, date.year) day_counter = ql.ActualActual() compounding = ql.Compounded freq = ql.Continuous zero_rate = curve.zeroRate(date, day_counter, compounding, freq).rate() return zero_rate
def getProcess(interest_rate, dividend_rate, underlying_price, volatility_rate): ################################################### ##2) Date setup ################################################### #Assumptions calendar = ql.UnitedStates() day_counter = ql.ActualActual() ################################################### ##3) #Curve setup ################################################### interest_curve = ql.FlatForward(valuation_date, ql.QuoteHandle(interest_rate), day_counter) dividend_curve = ql.FlatForward(valuation_date, ql.QuoteHandle(dividend_rate), day_counter) volatility_curve = ql.BlackConstantVol(valuation_date, calendar, ql.QuoteHandle(volatility_rate), day_counter) #Collate market data together u = ql.QuoteHandle(underlying_price) d = ql.YieldTermStructureHandle(dividend_curve) r = ql.YieldTermStructureHandle(interest_curve) v = ql.BlackVolTermStructureHandle(volatility_curve) return ql.BlackScholesMertonProcess(u, d, r, v)
def define_evaluation_grid(todays_date, simple_portfolio, number_of_months=12 * 6): """ @param todays_date: @param simple_portfolio: @param number_of_months: @return: """ evaluation_dates_grid = [ todays_date + ql.Period(i_month, ql.Months) for i_month in range(number_of_months) ] for deal in simple_portfolio: evaluation_dates_grid += deal[1] evaluation_dates_grid = np.unique(np.sort(evaluation_dates_grid)) evaluation_time_grid = np.vectorize(lambda x: ql.ActualActual( ).yearFraction(todays_date, x))(evaluation_dates_grid) # diff_evaluation_time_grid = evaluation_time_grid[1:] - evaluation_time_grid[:-1] return evaluation_dates_grid, evaluation_time_grid #, diff_evaluation_time_grid
def setUp(self): QuantLib.Settings.instance().setEvaluationDate( QuantLib.Date(2, 1, 2010)) self.settlement_days = 3 self.face_amount = 100.0 self.redemption = 100.0 self.issue_date = QuantLib.Date(2, 1, 2008) self.maturity_date = QuantLib.Date(2, 1, 2018) self.calendar = QuantLib.UnitedStates( QuantLib.UnitedStates.GovernmentBond) self.day_counter = QuantLib.ActualActual(QuantLib.ActualActual.Bond) self.sched = QuantLib.Schedule(self.issue_date, self.maturity_date, QuantLib.Period(QuantLib.Semiannual), self.calendar, QuantLib.Unadjusted, QuantLib.Unadjusted, QuantLib.DateGeneration.Backward, False) self.coupons = [0.05] self.bond = QuantLib.FixedRateBond(self.settlement_days, self.face_amount, self.sched, self.coupons, self.day_counter, QuantLib.Following, self.redemption, self.issue_date) self.flat_forward = QuantLib.FlatForward(self.issue_date, self.coupons[0], self.day_counter, QuantLib.Compounded, QuantLib.Semiannual) self.term_structure_handle = QuantLib.RelinkableYieldTermStructureHandle( self.flat_forward) bondEngine = QuantLib.DiscountingBondEngine(self.term_structure_handle) self.bond.setPricingEngine(bondEngine)
def commonYieldFromCleanPriceStatic(coupon, mat_date, issue_date, currency, settle_date, clean_price): dirty_price = BondLibrary.dirtyPriceFromCleanStatic( coupon, mat_date, issue_date, currency, settle_date, clean_price) tenor = ql.Period(BondLibrary.frequencyFromCurrency(currency)) # Now, with the dirty price, we calculate an "exact" common yield # Payments are now affected by national calendars calendar_local = BondLibrary.calendarFromCurrency(currency) businessConvention = ql.Following # from maturity date, going backwards dateGeneration = ql.DateGeneration.Backward # Shift to land on 28/29/30/31st monthEnd = False schedule = ql.Schedule(issue_date, mat_date, tenor, calendar_local, businessConvention, businessConvention, dateGeneration, monthEnd) settlementDays = 1 faceValue = 100.0 couponList = [coupon] dayCount = ql.ActualActual(ql.ActualActual.ISMA) fixedRateBond = ql.FixedRateBond(settlementDays, faceValue, schedule, couponList, dayCount) accint = fixedRateBond.accruedAmount(settle_date) clean_price = dirty_price + accint yyield = fixedRateBond.bondYield(clean_price, dayCount, ql.Continuous, ql.NoFrequency, settle_date) return yyield
def commonYieldFromSwapYield(currency, duration, issue_pydate, swap_yield): # NOTE: Use frequence of swap's fixed leg tenor = ql.Period(BondLibrary.swapFrequencyFromCurrency(currency)) # Now, with the dirty price, we calculate an "exact" common yield # Payments are now affected by national calendars calendar_local = BondLibrary.calendarFromCurrency(currency) businessConvention = ql.Following # from maturity date, going backwards dateGeneration = ql.DateGeneration.Backward # Shift to land on 28/29/30/31st monthEnd = False issue_date = convertToQLDate(issue_pydate) # WEIRD bug, just avoiding it. Happens even on leap years! if issue_pydate.month == 2 and issue_pydate.day == 29: mat_date = ql.Date(28, 2, issue_pydate.year + duration) else: mat_date = ql.Date(issue_pydate.day, issue_pydate.month, issue_pydate.year + duration) schedule = ql.Schedule(issue_date, mat_date, tenor, calendar_local, businessConvention, businessConvention, dateGeneration, monthEnd) settlementDays = 1 faceValue = 100.0 couponList = [swap_yield] dayCount = ql.ActualActual(ql.ActualActual.ISMA) fixedRateBond = ql.FixedRateBond(settlementDays, faceValue, schedule, couponList, dayCount) # accrued interest should be zero. clean_price = 100.0 yyield = fixedRateBond.bondYield(clean_price, dayCount, ql.Continuous, ql.NoFrequency, issue_date) return yyield
def setUp(self): QuantLib.Settings.instance().setEvaluationDate(QuantLib.Date(2,1,2010)) self.settlement_days = 3 self.face_amount = 100.0 self.redemption = 100.0 self.quote_handle = QuantLib.QuoteHandle(QuantLib.SimpleQuote(100.0)) self.issue_date = QuantLib.Date(2, 1, 2008) self.maturity_date = QuantLib.Date(2, 1, 2018) self.calendar = QuantLib.UnitedStates( QuantLib.UnitedStates.GovernmentBond) self.day_counter = QuantLib.ActualActual(QuantLib.ActualActual.Bond) self.sched = QuantLib.Schedule(self.issue_date, self.maturity_date, QuantLib.Period(QuantLib.Semiannual), self.calendar, QuantLib.Unadjusted, QuantLib.Unadjusted, QuantLib.DateGeneration.Backward, False) self.coupons = [0.05] self.bond_helper = QuantLib.FixedRateBondHelper(self.quote_handle, self.settlement_days, self.face_amount, self.sched, self.coupons, self.day_counter, QuantLib.Following, self.redemption, self.issue_date)
def setUp(self): self.settle_date = ql.Date.todaysDate() ql.Settings.instance().evaluationDate = self.settle_date self.dayCounter = ql.ActualActual() self.risk_free_handle = ql.YieldTermStructureHandle( ql.FlatForward(self.settle_date, 0.05, self.dayCounter)) self.dividend_yield_handle = ql.YieldTermStructureHandle( ql.FlatForward(self.settle_date, 0, self.dayCounter)) self.s0 = 50 self.omega = 0.000002 self.alpha = 0.024 self.beta = 0.93 self.gamma = 0.059 self.daysPerYear = 365.0 self.maturity = [90, 180] self.strike = [35, 40, 45, 50, 55, 60] self.lambda_values = [0.0, 0.1, 0.2] # correct values of analytic approximation self.analytic = [ [[15.4315, 10.5552, 5.9625, 2.3282, 0.5408, 0.0835], [15.8969, 11.2173, 6.9112, 3.4788, 1.3769, 0.4357]], [[15.4556, 10.6929, 6.2381, 2.6831, 0.7822, 0.1738], [16.0587, 11.5338, 7.3170, 3.9074, 1.7279, 0.6568]], [[15.8000, 11.2734, 7.0376, 3.6767, 1.5871, 0.5934], [16.9286, 12.3170, 8.0405, 4.6348, 2.3429, 1.0590]], ] # correct values of Monte Carlo self.mc_values = [ [[15.4332, 10.5453, 5.9351, 2.3521, 0.5597, 0.0776], [15.8910, 11.1772, 6.8827, 3.5096, 1.4196, 0.4502]], [[15.4580, 10.6433, 6.2019, 2.7513, 0.8374, 0.1706], [15.9884, 11.4139, 7.3103, 4.0497, 1.8862, 0.7322]], [[15.6619, 11.1263, 7.0968, 3.9152, 1.8133, 0.7010], [16.5195, 12.3181, 8.6085, 5.5700, 3.3103, 1.8053]], ]
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 Black76(pc, underlying, strike, impvol, ir, calc_date, expiry_date, param): # calendar = ql.UnitedStates() # bussiness_convention = ql.ModifiedFollowing # settlement_days = 2 if (calc_date < expiry_date): day_count = ql.ActualActual() interest_rate = ir yield_curve = ql.FlatForward(calc_date, interest_rate, day_count, ql.Compounded, ql.Continuous) discount = yield_curve.discount(expiry_date) T = day_count.yearFraction(calc_date, expiry_date) stdev = impvol * np.sqrt(T) if (pc.lower() == 'c'): strikepayoff = ql.PlainVanillaPayoff(ql.Option.Call, strike) else: strikepayoff = ql.PlainVanillaPayoff(ql.Option.Put, strike) black = ql.BlackCalculator(strikepayoff, underlying, stdev, discount) if (param.lower() == 'premium'): return black.value() elif (param.lower() == 'delta'): return black.delta(underlying) elif (param.lower() == 'gamma'): return black.gamma(underlying) elif (param.lower() == 'theta'): return black.theta(underlying, T) elif (param.lower() == 'vega'): return black.vega(T) else: return 'no answer for you!' else: return 0.0
class DayCount: ACT360 = ql.Actual360() ACT365Fixed = ql.Actual365Fixed() _30360BB = ql.Thirty360(ql.Thirty360.BondBasis) _30E360 = ql.Thirty360(ql.Thirty360.EurobondBasis) _30360US = ql.Thirty360(ql.Thirty360.USA) ACT365NL = ql.Actual365NoLeap() ACTACT = ql.ActualActual()
def to_dayCounter(s): if (s.upper() == 'ACTUAL360'): return ql.Actual360() if (s.upper() == 'ACTUAL365FIXED'): return ql.Actual365Fixed() if (s.upper() == 'ACTUALACTUAL'): return ql.ActualActual() if (s.upper() == 'ACTUAL365NOLEAP'): return ql.Actual365NoLeap() if (s.upper() == 'BUSINESS252'): return ql.Business252() if (s.upper() == 'ONEDAYCOUNTER'): return ql.OneDayCounter() if (s.upper() == 'SIMPLEDAYCOUNTER'): return ql.SimpleDayCounter() if (s.upper() == 'THIRTY360'): return ql.Thirty360()
def credit_bond_risk_measures(bond, cleanprice, curve): risks = list() bump_size = 1e-4 bond_yield = bond.bondYield(cleanprice, ql.ActualActual(), ql.Compounded, ql.Semiannual) risks.append(('YieldToMaturity', bond_yield)) rate = ql.InterestRate(bond_yield, ql.ActualActual(), ql.Compounded, ql.Semiannual) risks.append(('MacaulayDuration', ql.BondFunctions.duration(bond, rate, ql.Duration.Macaulay))) risks.append(('ModifiedDuration', ql.BondFunctions.duration(bond, rate, ql.Duration.Modified))) risks.append(('Convexity', ql.BondFunctions.convexity(bond, rate))) nodes = [ ql.Period(1, ql.Months), ql.Period(3, ql.Months), ql.Period(6, ql.Months), ql.Period(1, ql.Years), ql.Period(2, ql.Years), ql.Period(3, ql.Years), ql.Period(5, ql.Years), ql.Period(10, ql.Years), ql.Period(15, ql.Years), ql.Period(30, ql.Years) ] dates = [ql.Date.todaysDate() + node for node in nodes] buckets = ['1M', '3M', '6M', '1Y', '2Y', '3Y', '5Y', '10Y', '15Y', '30Y'] discount_handle = ql.RelinkableYieldTermStructureHandle(curve) bond.setPricingEngine(ql.DiscountingBondEngine(discount_handle)) base_price = bond.NPV() spreads = [ql.SimpleQuote(0.0) for i in range(len(nodes))] cnt = 0 for spread in spreads: spread.setValue(bump_size) bumped_curve = ql.SpreadedLinearZeroInterpolatedTermStructure( ql.YieldTermStructureHandle(curve), [ql.QuoteHandle(q) for q in spreads], dates) discount_handle.linkTo(bumped_curve) bumped_price = bond.NPV() risks.append(('KeyRateDuration_{}'.format(buckets[cnt]), (bumped_price - base_price) / bump_size)) spread.setValue(0.0) cnt += 1 return risks
def Set_Process(self, exercise_type): '''定义Payoff''' if self.option_type == 'call': put_or_call = ql.Option.Call elif self.option_type == 'put': put_or_call = ql.Option.Put else: print('unknown option type:', self.option_type) return (-1) payoff = ql.PlainVanillaPayoff( put_or_call, self.strike_price.value()) #根据call/put,产生相应Payoff对象 '''定义Exercise''' #shift expiry date forward by 1 day, so that calculation can be done on the expiry day self.exercise_type = exercise_type expiry_date_1 = self.expiry_date + dt.timedelta(days=1) eDate = ql.Date(expiry_date_1.day, expiry_date_1.month, expiry_date_1.year) self.valuation_date = min(self.expiry_date, self.valuation_date) self.vDate = ql.Date(self.valuation_date.day, self.valuation_date.month, self.valuation_date.year) if self.exercise_type == 'E': exercise = ql.EuropeanExercise(eDate) elif self.exercise_type == 'A': exercise = ql.AmericanExercise(self.vDate, eDate) else: print('unknown option type:', self.exercise_type) return (-1) '''定义Calendar''' #Set the valuation date, by default it will use today's date ql.Settings.instance().evaluationDate = self.vDate calendar = ql.China() day_counter = ql.ActualActual() '''定义Option,输入PayOff与Exercise''' option = ql.VanillaOption(payoff, exercise) '''定义TermStructure(Vol,Dividend,Int)''' #dividend_curve = ql.FlatForward(self.vDate, self.dividend_rate.value(), day_counter) #interest_curve = ql.FlatForward(self.vDate, self.interest_rate.value(), day_counter) #volatility_curve = ql.BlackConstantVol(self.vDate, calendar, self.volatility.value(), day_counter) dividend_curve = ql.FlatForward(0, ql.TARGET(), ql.QuoteHandle(self.dividend_rate), day_counter) interest_curve = ql.FlatForward(0, ql.TARGET(), ql.QuoteHandle(self.interest_rate), day_counter) volatility_curve = ql.BlackConstantVol(0, ql.TARGET(), ql.QuoteHandle(self.volatility), day_counter) u = ql.QuoteHandle(self.underlying_price) d = ql.YieldTermStructureHandle(dividend_curve) r = ql.YieldTermStructureHandle(interest_curve) v = ql.BlackVolTermStructureHandle(volatility_curve) process = ql.BlackScholesMertonProcess(u, d, r, v) return option, process
def callablebond_price_with_interest_lattice(callable, price, curve, reversion, volatility, grid_points): model = ql.HullWhite(ql.YieldTermStructureHandle(curve), reversion, volatility) engine = ql.TreeCallableFixedRateBondEngine(model, grid_points) callable.setPricingEngine(engine) cleanPrice = callable.cleanPrice() oas = callable.OAS(price, ql.YieldTermStructureHandle(curve), ql.ActualActual(), ql.Compounded, ql.Semiannual) return cleanPrice, oas
def create_range(values): day_count = ql.ActualActual().dayCount(values["startDate"], values["expirationdate"]) standard_deviation = values["spotprice"] * values["volatility"] * ( math.sqrt(day_count / 365)) max_value = values["spotprice"] + (standard_deviation * 2) min_value = values["spotprice"] - (standard_deviation * 2) if (min_value < 0): min_value = 0 return max_value, min_value
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 __init__(self, ccy, tenor): if tenor in string.digits: tenor = '_' + tenor self.ccy = ccy.upper() self.tenor = tenor self.name = h5_irc_node + '_' + ccy + '_' + tenor self.name = self.name.lower() self.key_ts = du.h5_ts_node + '/' + h5_irc_node + '/' + self.ccy \ + '/' + tenor.upper() self._daycounter = ql.ActualActual() self.values = None super(IRCurve, self).__init__(self.key_ts)
def extract_info(curve, dates, valDate, name='spot_rate'): #helper function to extract key rate information from a QuantLib curve to a panda dataframe rates = [] for t in range(0, len(dates)): #years=years+1 date = dates[t] #nb years between valuation date and future date yearPassed = ql.ActualActual().yearFraction(valDate, date) rates.append(curve.zeroRate(yearPassed, ql.Compounded).rate()) #reutrns a dataframe of date & scenario curve return pd.DataFrame(list(zip(dates, rates)), columns=['date', name])
def dayCountForBondFromCurrency(currency): if currency == "AUD": return ql.ActualActual(ql.ActualActual.Bond) elif currency == "CAD": return ql.ActualActual(ql.ActualActual.Bond) # ?? Actual365Fixed? elif currency == "CHF": return ql.Thirty360(ql.Thirty360.European) elif currency == "DEM": return ql.Thirty360(ql.Thirty360.European) elif currency == "EUR": return ql.ActualActual(ql.ActualActual.Euro) elif currency == "GBP": return ql.ActualActual(ql.ActualActual.Bond) elif currency == "JPY": return ql.ActualActual(ql.ActualActual.Actual365) elif currency == "NOK": return ql.Thirty360(ql.Thirty360.European) # Not clear # return ql.ActualActual(ql.ActualActual.Actual365) elif currency == "NZD": return ql.ActualActual(ql.ActualActual.Actual365) # Not clear elif currency == "SEK": return ql.Thirty360(ql.Thirty360.European) # Not clear # return ql.ActualActual(ql.ActualActual.Bond) elif currency == "USD": return ql.Thirty360(ql.Thirty360.BondBasis) else: raise Exception("no daycount for currency:" + currency)
def Simulate_Heston_QuantLib( NumOfAssets=10, TimeSteps=30, dt=1. / 365, S0=100, V0=0.04, r=0.025, kappa=1.5, theta=0.04, sigma=0.30, rho=-0.9): # V0=0.48, kappa=1.2, theta=0.25, sigma=0.80, rho=-0.64 today = ql.Date(15, ql.October, 2008) riskFreeRate = ql.FlatForward(today, r, ql.ActualActual()) dividendRate = ql.FlatForward(today, 0.0, ql.ActualActual()) # discretization = Reflection # PartialTrunction, FullTruncation, Reflection, ExactVariance hp = ql.HestonProcess( ql.YieldTermStructureHandle(riskFreeRate), ql.YieldTermStructureHandle(dividendRate), ql.QuoteHandle(ql.SimpleQuote(S0)), # S0 V0, # v0 kappa, # kappa theta, # theta sigma, # sigma rho, # rho ) times = [n * dt for n in range(TimeSteps)] rsg = ql.GaussianRandomSequenceGenerator( ql.UniformRandomSequenceGenerator(2 * (len(times) - 1), ql.UniformRandomGenerator())) mpg = ql.GaussianMultiPathGenerator(hp, times, rsg, brownianBridge=False) S = np.zeros((len(times), NumOfAssets)) V = np.zeros((len(times), NumOfAssets)) for i in range(NumOfAssets): sample = mpg.next() multipath = sample.value() S[:, i] = multipath[0] V[:, i] = multipath[1] return S, V
def str2dc(s): s = s.lower() if s=="actual365fixed" or s=="act365": return ql.Actual365Fixed() elif s=="actualactual" or s=="actact": return ql.ActualActual() elif s=="actual360" or s=="act360": return ql.Actual360() elif s=="Thirty360" or s=="30360": return ql.Thirty360() else: print("Period String Error")
def spot_curve_to_par_rate( curve, quote_dates=None, calc_date=ql.Date.todaysDate(), daycounter=ql.ActualActual()): # par rate approximation ts = ql.RelinkableYieldTermStructureHandle(curve) sum = 0.0 dates = curve.dates() if quote_dates == None else quote_dates for i in range(1, len(dates)): yrs = daycounter.yearFraction(dates[i - 1], dates[i]) sum += ts.discount(dates[i]) * yrs result = ts.discount(dates[0]) - ts.discount(dates[-1]) return 100 * (result / sum)
def init(): yts = ql.RelinkableYieldTermStructureHandle() instruments = [ ('depo', '6M', 0.025), ('fra', '6M', 0.03), ('swap', '2Y', 0.032), ('swap', '3Y', 0.035) ] helpers = ql.RateHelperVector() index = ql.Euribor6M(yts) for instrument, tenor, rate in instruments: if instrument == 'depo': helpers.append( ql.DepositRateHelper(rate, index) ) if instrument == 'fra': monthsToStart = ql.Period(tenor).length() helpers.append( ql.FraRateHelper(rate, monthsToStart, index) ) if instrument == 'swap': swapIndex = ql.EuriborSwapIsdaFixA(ql.Period(tenor)) helpers.append( ql.SwapRateHelper(rate, swapIndex)) curve = ql.PiecewiseLogCubicDiscount(2, ql.TARGET(), helpers, ql.ActualActual()) yts.linkTo(curve) engine = ql.DiscountingSwapEngine(yts) tenor = ql.Period('2y') fixedRate = 0.05 forwardStart = ql.Period("2D") swap = ql.MakeVanillaSwap(tenor, index, fixedRate, forwardStart, Nominal=10e6, pricingEngine=engine) airRate = swap.fairRate() npv = swap.NPV() #print(f"Fair swap rate: {fairRate:.3%}") print(f"Swap NPV: {npv:,.3f}") import pandas as pd pd.options.display.float_format = "{:,.2f}".format cashflows = pd.DataFrame({ 'date': cf.date(), 'amount': cf.amount() } for cf in swap.leg(1)) print(cashflows) cashflows = pd.DataFrame({ 'nominal': cf.nominal(), 'accrualStartDate': cf.accrualStartDate().ISO(), 'accrualEndDate': cf.accrualEndDate().ISO(), 'rate': cf.rate(), 'amount': cf.amount() } for cf in map(ql.as_coupon, swap.leg(1))) print(cashflows)
def spot_rate_match(guess, ScenCurve, baseCurve, todayDate, spotDate, spreads, target, indx): #return futureDate = spotDate baseCurveHandle = ql.YieldTermStructureHandle(baseCurve) spreads[indx].setValue(guess) yearPassed = ql.ActualActual().yearFraction(todayDate, spotDate) #yearPassed=indx scenHandle = ql.YieldTermStructureHandle(ScenCurve) scenTarget = scenHandle.zeroRate(yearPassed, ql.Compounded).rate() baseTarget = baseCurveHandle.zeroRate(yearPassed, ql.Compounded).rate() return scenTarget - baseTarget - target
def get_rates(curve, calc_date=ql.Date.todaysDate(), daycounter=ql.ActualActual()): spots, tenors, quote_dates = list(), list(), list() for d in curve.dates(): yrs = daycounter.yearFraction(calc_date, d) compounding = ql.Compounded freq = ql.Semiannual zero_rate = curve.zeroRate(yrs, compounding, freq) quote_dates.append(d) tenors.append(yrs) eq_rate = zero_rate.equivalentRate(daycounter, compounding, freq, calc_date, d).rate() spots.append(100 * eq_rate) return quote_dates, tenors, spots