def calc_futures_payoff(self, maturity=None): ''' calculate futures payoff given updated maturity as year fraction ''' if maturity and isinstance( maturity, (str, intdate.bdte.BusinessDate, intdate.dt.date)): mat = intdate.convert_date_bdte(maturity, self.options) else: mat = self.maturity mult = 0.01 * intdate.calc_bdte_diff(mat, self.options, self.reset) if mat != max(self.cash_flow_df.index): print("Warning -- mismatch %s %s shape %d" % (mat.to_date(), max( self.cash_flow_df.index), self.cash_flow_df.shape[0])) if self.cash_flow_df.shape[0] == 1: self.cash_flow_df.loc[mat.to_date(), 'maturity'] =\ intdate.calc_bdte_diff(mat, self.options) elif self.cash_flow_df.shape[0] == 2: self.cash_flow_df.index = [self.reset.to_date(), mat.to_date()] self.cash_flow_df.loc[mat.to_date(), 'maturity'] =\ intdate.calc_bdte_diff(mat, self.options) else: raise ValueError("Faulty dimansions for futures contract") self.cash_flow_df.loc[mat.to_date(), 'time_diff'] =\ self.cash_flow_df.loc[mat.to_date(), 'maturity'] -\ self.cash_flow_df.loc[self.reset.to_date(), 'maturity'] self.cash_flow_df.loc[mat.to_date(), 'CF'] = self.princ +\ mult*self.princ*self.spot
def init_prices(self, prices): ''' results in the case of yields ''' mult = 100.0 for i in np.arange(0, self.matrix.shape[0]): sched = self.schedule[i] if i == 0: self.matrix.loc[sched, 'zero'] = 1.0 schedprev = 0 else: mat = intdate.calc_bdte_diff(self.schedule[i], self.date_spec, self.schedule[0]) self.matrix.loc[sched, 'yield'] = -mult * np.log( prices[i - 1] / mult) / mat self.matrix.loc[sched, 'maturity'] = mat self.matrix.loc[sched, 'date_diff'] = intdate.calc_bdte_diff( self.schedule[i], self.date_spec, self.schedule[i - 1]) if i > 1: self.matrix.loc[sched, ['forward', 'yield_hat']] = self.forward( sched, schedprev) else: self.matrix.loc[sched, 'yield_hat'] = self.f0(mat) self.matrix.loc[sched, 'forward'] = self.matrix.loc[sched, 'yield_hat'] self.matrix.loc[sched, 'zero'] = np.exp( -self.matrix.loc[sched, 'yield_hat'] * mat / mult) schedprev = sched
def load_data_row(options, df=None, dates=None, position=0, rate=0.15, date='2012-10-02', typ='LIBOR', ref_position=-1, dbg=True): ''' DEPRECATED -- see curve constructor Loader -- operates based on typ ''' if df is not None and isinstance(df, np.ndarray) and\ int(df.size / len(df)) == len(options['control']["columns"]): if dbg: print("Fine Dimensions") else: df, dates = build_arrays(options, dbg=dbg) dates[position] = dt.datetime.strptime(date, options['control']["date_format"]) if "origin" in options['control']["columns"]: df[position][4] = intbase.load_types.MARKET.value if typ.upper().startswith('LIBOR'): df[position][0] = intdate.calc_bdte_diff(dates[position], options) df[position][1] = rate df[position][2] = intbase.calc_libor_zero_coupon(rate, df[position][0]) df[position][3] = intbase.rate_instruments.LIBOR.value elif typ.upper().startswith("FUTUR"): df[position][0] = intdate.calc_bdte_diff(dates[position], options) df[position][1] = intbase.futures_rate(rate) if 0 <= ref_position < position: df[position][2] = intbase.calc_forward_zero_coupon( df[position][1], (df[position][0] - df[ref_position][0]), df[ref_position][2]) df[position][3] = intbase.rate_instruments.FUTURE.value elif typ.upper().startswith("SWAP"): df[position][0] = intdate.calc_bdte_diff(dates[position], options) df[position][1] = rate if 0 <= ref_position < position: df[position][2] = intbase.calc_swap_zero_coupon( rate, df, position, ref_position) df[position][3] = intbase.rate_instruments.SWAP.value else: raise ValueError("Type not supported") return df, dates
def determine_reference_date(self, instrument): ''' deterimines reference date and maturity ''' refereposition = None maturity = np.nan if instrument in self.options['instruments'].keys(): reference_date = self.options['instruments'][instrument]['ref_date'] elif int(self.results.loc[instrument]['origin']) == 2: x0_nme = self.options['interpolated_instruments'][instrument]['reference_positions'][0] x1_nme = self.options['interpolated_instruments'][instrument]['reference_positions'][1] if self.options['instruments'][x0_nme]['date'] <=\ self.options['instruments'][x1_nme]['date']: x1_nme = x0_nme reference_date = self.options['instruments'][x1_nme]['ref_date'] else: raise ValueError("Faulty FUTURES") refereposition = self.determine_instrument_name(reference_date) # print(refereposition, inst, "\n") # print(self.results.loc[inst], self.results.loc[refereposition]) if not isinstance(refereposition, bool) and refereposition in self.results.index: maturity = self.results.loc[refereposition, 'maturity'] else: maturity = intdate.calc_bdte_diff(reference_date, self.options) return reference_date, maturity
def append_swaps(self): ''' Appends SWAPs interpolated SWAPs ''' self.next_swap_key = self.next_swap_key - 1 for _, item in self.options['interpolated_swaps'].items(): strt = intdate.convert_date_bdte(item['lower_date'], self.options) end = intdate.convert_date_bdte(item['upper']['date'], self.options) per = intdate.convert_period(item['upper']['frequency']) sched = bdte.BusinessSchedule(strt, end, per) if 'control' in self.options.keys() and\ 'date_adjust' in self.options['control'].keys() and\ self.options['control']['date_adjust'] in ['follow', 'flw', 'modified']: # key adjusts sched for business date -- print("Here") sched.adjust(self.options['control']['date_adjust']) date_diff_final = intdate.calc_bdte_diff_int( end, strt, self.options, dbg=False) if self.dbg: print("## ", self.next_swap_key, strt, end, date_diff_final) self.next_swap_key = (self.next_swap_key + date_diff_final) if 'control' in self.options.keys() and 'date_adjust' in\ self.options['control'].keys(): if not strt.is_business_day(): strt.adjust(self.options['control']['date_adjust']) if not end.is_business_day(): end.adjust(self.options['control']['date_adjust']) date_diff_dbl = intdate.calc_bdte_diff(end, self.options, strt) key = "".join(["SWAP", str(self.next_swap_key)]) # self.calc_next_swap_key(key) self.instruments[key] = swapconv.build_swap(key, item['upper'], self.options, dbg=False) self.append_instrument_dates_swap(key) swap_key = self.find_swap(min(sched)) swap_strt = int(swap_key.upper().split("AP")[1]) for loc, dte in zip(np.arange(0, len(sched)), sched): if min(sched) < dte < max(sched): new_swap_dict, new_swap_name = swapconv.generate_swap_dictionary( self.options, maturity=dte, swap_start=strt, swapid=(swap_strt + loc), reference="SWAP1", rates=[[0.0, date_diff_dbl], [self.instruments[swap_key].r_swap, self.instruments[key].r_swap]], dbg=False) self.instruments[new_swap_name] = swapconv.build_swap( new_swap_name, new_swap_dict, self.options, dbg=False) self.append_instrument_dates_swap(new_swap_name)
def init_forward(self, rates): ''' inittializes structure in the case of forwards ''' mult = 100.0 # calculate results in percents for i in np.arange(0, self.matrix.shape[0]): if i == 0: self.matrix.loc[i, 'zero'] = 1.0 else: self.matrix.loc[i, 'forward'] = rates[i - 1] self.matrix.loc[i, 'maturity'] = intdate.calc_bdte_diff( self.schedule[i], self.date_spec, self.schedule[0]) self.matrix.loc[i, 'date_diff'] = intdate.calc_bdte_diff( self.schedule[i], self.date_spec, self.schedule[i - 1]) self.matrix.loc[i, 'zero'] = intbase.calc_forward_zero_coupon( self.matrix.loc[i, 'forward'], self.matrix.loc[i, 'date_diff'], self.matrix.loc[(i - 1), 'zero']) self.matrix.loc[i, 'yield'] = mult*(-1)*np.log(self.matrix.loc[i, 'zero'])/\ self.matrix.loc[i, 'maturity']
def __init__(self, name, strike, swap, options, dbg=False): self.options = options self.debug = dbg if isinstance(swap, intrate.swap): self.reference_instrument = swap self.maturity = swap.reset elif isinstance(swap, json): self.maturity = intdate.convert_date_bdte(swap['reset_date'], options) self.reference_instrument = build_swap("SWAP", swap, options, dbg=self.debug) else: raise ValueError("Must be type JSON or swap") self.maturity_dbl = intdate.calc_bdte_diff(self.maturity, self.options) self.strike = strike self.name = name self.notional = self.reference_instrument.princ
def load_data_row(self, position='LIBOR1', rate=0.15, date='2012-10-02', typ='LIBOR', origin=None): ''' Loader -- operates based on typ ''' if "origin" in self.options['control']["columns"] and origin is None: self.results.loc[position]['origin'] = intbase.load_types.MARKET.value elif "origin" in self.options['control']["columns"] and\ isinstance(origin, (int, float)): self.results.loc[position]['origin'] = origin if isinstance(date, float): mat = date else: mat = intdate.calc_bdte_diff(date, self.options) # print(position, date, mat) if typ.upper().startswith('LIBOR'): self.results.loc[position]['maturity'] = mat self.results.loc[position]['rate'] = rate self.results.loc[position]['type'] = intbase.rate_instruments.LIBOR.value elif typ.upper().startswith("FUTUR"): self.results.loc[position]['maturity'] = mat self.results.loc[position]['rate'] = intbase.futures_rate(rate) self.results.loc[position]['type'] = intbase.rate_instruments.FUTURE.value elif typ.upper().startswith("SWAP"): self.results.loc[position]['maturity'] = mat self.results.loc[position]['rate'] = rate self.results.loc[position]['type'] = intbase.rate_instruments.SWAP.value elif typ.upper().startswith("FIXEDCOUPONBO") or typ.upper().startswith("ZERO"): self.results.loc[position]['maturity'] = mat self.results.loc[position]['rate'] = rate self.results.loc[position]['type'] = intbase.rate_instruments.ZERO_COUPON.value if\ typ.upper().startswith("ZERO") else intbase.rate_instruments.FIXED_RATE_BOND.value else: raise ValueError("Type not supported") self.results.loc[position, 'loaded'] = 1
def interpolate_instruments(self, result_position, item_dict): ''' Simple linear interpolator that constructs interpolated instrument of same time result_position: location (numpy -- row) where results stored, determines location of date result_date: maturity date of instrument / rate -- determines weightings position1: location in df of left value used in interpolation position2: location in df of right valued used in interpolation ''' if self.results.loc[item_dict['reference_positions'][0]]['maturity'] <=\ self.results.loc[item_dict['reference_positions'][1]]['maturity']: position1 = item_dict['reference_positions'][0] position2 = item_dict['reference_positions'][1] else: position2 = item_dict['reference_positions'][0] position1 = item_dict['reference_positions'][1] if int(self.results.loc[position1]['type']) == int(self.results.loc[position2]['type']): if 'type' in item_dict.keys(): typ = item_dict['type'] else: typ = self.options['instruments'][position1]['type'] mat = intdate.calc_bdte_diff(item_dict['date'], self.options) dist = self.results.loc[position2]['maturity'] - self.results.loc[position1]['maturity'] q = (mat - self.results.loc[position1]['maturity']) / dist rate = (1- q)*self.results.loc[position1]['rate'] +\ q*self.results.loc[position2]['rate'] if result_position.upper().startswith('LIBOR'): self.load_data_row(position=result_position, rate=rate, date=item_dict['date'], typ='LIBOR', origin=intbase.load_types.INTERPOLATED.value) else: if position1 in self.options['instruments'].keys(): if typ.upper().startswith("FUTUR"): self.instruments[result_position] = intrate.interest_rate_future( result_position, rate, maturity=item_dict['date'], reset=self.instruments[position1].reset, frequency=self.instruments[position1].frequency, options=self.options, dbg=False) self.load_data_row( position=result_position, rate=self.instruments[result_position].rate, date=self.instruments[result_position].maturity, typ='FUTURE', origin=intbase.load_types.INTERPOLATED.value) else: self.load_data_row(position=result_position, rate=rate, date=item_dict['date'], typ=typ, origin=intbase.load_types.INTERPOLATED.value) else: print("Warning no item %s loaded" % (result_position)) if self.dbg: print("Interpolate Results: %f %f %d %d" % ( self.results.loc[result_position]['maturity'], self.results.loc[result_position]['rate'], int(self.results.loc[result_position]['type']), int(self.results.loc[result_position]['origin']))) else: raise ValueError("(interpolate_instruments): Instrument Types MUST MATCH")
def generate_swap_dictionary(options, maturity, swap_start=None, swapid=0, reference="SWAP1", rates=None, princ=1.0, frequency='Y', reset_date=None, to_equal_T0=False, dbg=False): ''' constructs dictionary of swap assumptions necessary to construction of swap instrument options: python dict including control and instruments dictionaries maturity: maturity of constructed swap swap_start: aplies in case interpolating between two swap rates swapid: string applied to identify SWAP reference: refers to swap of same name in options['instruments'] rates: asscepts (1) single float or (2) 2x2 conformable matrix object NOTE: items procede by asterisk are applied only in case not reference object provided princ (*): principal frquency (*): frequency of swap payments reset_date (*) date (date conformable object) of reset to_equal_T0 (*) bool indicating whether valuation time equals reset date dbg: debugging indicator returns: (1) swap specfication dict (2) swap_name ''' if reference and isinstance(reference, str): if 'instruments' in options.keys( ) and reference in options['instruments'].keys(): new_swap_dict = options['instruments'][reference].copy() else: raise ValueError( "genrate_swap_dictionary: missing instruments + reference") else: if dbg: print("Warning -- applying default SWAP definition ") new_swap_dict = { 'type': 'SWAP', 'princ': princ, 'frequency': frequency, 'reference_rate': 'LIBOR', 'to_equal_T0': to_equal_T0 } new_swap_dict['reset_date'] = reset_date new_swap_dict['date'] = maturity if rates and isinstance(rates, float) and np.isfinite(rates): new_swap_dict['rate'] = rates new_swap_dict['is_market'] = 1 elif rates and isinstance(rates, (list, np.ndarray)) and np.size(rates) > 3: new_swap_dict['is_market'] = 0 if isinstance(rates, list) and len(rates) == 2: np_rates = np.array(rates, ndmin=2) elif isinstance(rates, np.ndarray): np_rates = rates.copy() else: raise ValueError("genrate_swap_dictionary: faulty rates spec") date_diff_dbl2 = intdate.calc_bdte_diff(maturity, options, swap_start) new_swap_dict['rate'] = sci.interp(date_diff_dbl2, xp=np_rates[0], fp=np_rates[1]) else: new_swap_dict['rate'] = np.nan new_swap_dict['is_market'] = 0 print("Warning (genrate_swap_dictionary): faulty rates specifcation") if swapid > 0: new_swap_name = "".join(["SWAP", str(swapid)]) else: new_swap_name = "SWAP" return new_swap_dict, new_swap_name
def interpolate_instruments(result_position, result_date, position1, position2, options, df, dates, dbg=False): ''' Simple linear interpolator that constructs interpolated instrument of same time result_position: location (numpy -- row) where results stored, determines location of date result_date: maturity date of instrument / rate -- determines weightings position1: location in df of left value used in interpolation position2: location in df of right valued used in interpolation options: controls dictionary df: numpy containing interpolation inputs and result interpolation dates: date numpy 9.96400000e+01array containing dates (in dt.datetime) dbg: determines whether to output intermediate results from interpolation ''' if int(df[position1][3]) == int(df[position2][3]): if "origin" in options['control']["columns"]: df[result_position][4] = intbase.load_types.INTERPOLATED.value if isinstance(result_date, str): dates[result_position] = dt.datetime.strptime( result_date, options['control']["date_format"]) elif isinstance(result_date, bdte.BusinessDate): init_date = result_date.to_date() dates[result_position] = dt.datetime(init_date.year, init_date.month, init_date.day, 0, 0) else: dates[result_position] = result_date df[result_position][0] = intdate.calc_bdte_diff( dates[result_position], options) dist = df[position2][0] - df[position1][0] q = (df[result_position][0] - df[position1][0]) / dist df[result_position][1] = (1 - q) * df[position1][1] + q * df[position2][1] df[result_position][3] = df[position1][3] if int(df[position1][3]) == 1: df[result_position][2] = intbase.calc_libor_zero_coupon( df[result_position][1], df[result_position][0]) elif int(df[position1][3]) == 2 or int(df[position1][3]) == 3: df[result_position][2] = intbase.calc_forward_zero_coupon( df[result_position][1], (df[result_position][0] - df[position1][0]), df[position1][2]) if dbg: print("Interpolate Results: %d %f (%f) %f %d" % (df[result_position][0], df[result_position][1], (df[result_position][0] - df[position1][0]), df[result_position][2], int(df[result_position][3]))) else: raise ValueError( "(interpolate_instruments): Instrument Types MUST MATCH") return df, dates