def __init__(self, settlement_date, maturity_date, coupon_spec, start_date=None, first_coupon_date=None, penultimate_coupon_date=None, holiday_calendar=None, dtype=None, name=None): """Initialize a batch of fixed coupon bonds. Args: settlement_date: A rank 1 `DateTensor` specifying the settlement date of the bonds. maturity_date: A rank 1 `DateTensor` specifying the maturity dates of the bonds. The shape of the input should be the same as that of `settlement_date`. coupon_spec: A list of `FixedCouponSpecs` specifying the coupon payments. The length of the list should be the same as the number of bonds being created. start_date: An optional `DateTensor` specifying the dates when the interest starts to accrue for the coupons. The input can be used to specify a forward start date for the coupons. The shape of the input correspond to the numbercof instruments being created. Default value: None in which case the coupons start to accrue from the `settlement_date`. first_coupon_date: An optional rank 1 `DateTensor` specifying the dates when first coupon will be paid for bonds with irregular first coupon. penultimate_coupon_date: An optional rank 1 `DateTensor` specifying the dates when the penultimate coupon (or last regular coupon) will be paid for bonds with irregular last coupon. holiday_calendar: An instance of `dates.HolidayCalendar` to specify weekends and holidays. Default value: None in which case a holiday calendar would be created with Saturday and Sunday being the holidays. dtype: `tf.Dtype`. If supplied the dtype for the real variables or ops either supplied to the bond object or created by the bond object. Default value: None which maps to the default dtype inferred by TensorFlow. name: Python str. The name to give to the ops created by this class. Default value: `None` which maps to 'bond'. """ self._name = name or 'bond' if holiday_calendar is None: holiday_calendar = dates.create_holiday_calendar( weekend_mask=dates.WeekendMask.SATURDAY_SUNDAY) with tf.name_scope(self._name): self._dtype = dtype self._settlement_date = dates.convert_to_date_tensor( settlement_date) self._maturity_date = dates.convert_to_date_tensor(maturity_date) self._holiday_calendar = holiday_calendar self._setup(coupon_spec, start_date, first_coupon_date, penultimate_coupon_date)
def __init__(self, start_date, maturity_date, pay_leg, receive_leg, holiday_calendar=None, dtype=None, name=None): """Initialize a batch of IRS contracts. Args: start_date: A rank 1 `DateTensor` specifying the dates for the inception (start of the accrual) of the swap contracts. The shape of the input correspond to the number of instruments being created. maturity_date: A rank 1 `DateTensor` specifying the maturity dates for each contract. The shape of the input should be the same as that of `start_date`. pay_leg: A scalar or a list of either `FixedCouponSpecs` or `FloatCouponSpecs` specifying the coupon payments for the payment leg of the swap. If specified as a list then the length of the list should be the same as the number of instruments being created. If specified as a scalar, then the elements of the namedtuple must be of the same shape as (or compatible to) the shape of `start_date`. receive_leg: A scalar or a list of either `FixedCouponSpecs` or `FloatCouponSpecs` specifying the coupon payments for the receiving leg of the swap. If specified as a list then the length of the list should be the same as the number of instruments being created. If specified as a scalar, then the elements of the namedtuple must be of the same shape as (or compatible with) the shape of `start_date`. holiday_calendar: An instance of `dates.HolidayCalendar` to specify weekends and holidays. Default value: None in which case a holiday calendar would be created with Saturday and Sunday being the holidays. dtype: `tf.Dtype`. If supplied the dtype for the real variables or ops either supplied to the IRS object or created by the IRS object. Default value: None which maps to the default dtype inferred by TensorFlow. name: Python str. The name to give to the ops created by this class. Default value: `None` which maps to 'interest_rate_swap'. """ self._name = name or 'interest_rate_swap' if holiday_calendar is None: holiday_calendar = dates.create_holiday_calendar( weekend_mask=dates.WeekendMask.SATURDAY_SUNDAY) with tf.name_scope(self._name): self._dtype = dtype self._start_date = dates.convert_to_date_tensor(start_date) self._maturity_date = dates.convert_to_date_tensor(maturity_date) self._holiday_calendar = holiday_calendar self._floating_leg = None self._fixed_leg = None self._pay_leg = self._setup_leg(pay_leg) self._receive_leg = self._setup_leg(receive_leg) self._is_payer = isinstance(self._pay_leg, cs.FixedCashflowStream)
def __init__(self, valuation_date: types.DateTensor, expiries: types.DateTensor, strikes: types.FloatTensor, volatilities: types.FloatTensor, daycount_convention: Optional[ _DayCountConventionsProtoType] = None, dtype: Optional[tf.DType] = None, name: Optional[str] = None): """Initializes the volatility surface. Args: valuation_date: A `DateTensor` specifying the valuation (or settlement) date for the curve. expiries: A `DateTensor` containing the expiry dates on which the implied volatilities are specified. Should have a compatible shape with valuation_date. strikes: A `Tensor` of real dtype specifying the strikes corresponding to the input maturities. The shape of this input should match the shape of `expiries`. volatilities: A `Tensor` of real dtype specifying the volatilities corresponding to the input maturities. The shape of this input should match the shape of `expiries`. daycount_convention: `DayCountConventions` to use for the interpolation purpose. Default value: `None` which maps to actual/365 day count convention. dtype: `tf.Dtype`. Optional input specifying the dtype of the `rates` input. name: Python str. The name to give to the ops created by this function. Default value: `None` which maps to 'rate_curve'. """ self._name = name or "VolatilitySurface" self._dtype = dtype or tf.float64 with tf.name_scope(self._name): self._daycount_convention = (daycount_convention or _DayCountConventions.ACTUAL_365) self._day_count_fn = utils.get_daycount_fn( self._daycount_convention) self._valuation_date = dateslib.convert_to_date_tensor( valuation_date) self._expiries = dateslib.convert_to_date_tensor(expiries) self._strikes = tf.convert_to_tensor(strikes, dtype=self._dtype, name="strikes") self._volatilities = tf.convert_to_tensor(volatilities, dtype=self._dtype, name="volatilities") expiry_times = self._day_count_fn(start_date=self._valuation_date, end_date=self._expiries, dtype=self._dtype) self._interpolator = interpolation_2d.Interpolation2D( expiry_times, strikes, volatilities, dtype=self._dtype)
def discount_factor( self, interpolation_dates: Optional[types.DateTensor] = None, interpolation_times: Optional[types.FloatTensor] = None, name: Optional[str] = None): """Returns discount factors at `interpolation_dates`.""" if interpolation_dates is None and interpolation_times is None: raise ValueError( "Either interpolation_dates or interpolation times " "must be supplied.") if interpolation_dates is not None: interpolation_dates = dateslib.convert_to_date_tensor( interpolation_dates) times = self._get_time(interpolation_dates) else: times = tf.convert_to_tensor(interpolation_times, self._dtype) if self._interpolate_rates: rates = self._interpolator(times, self._times, self.discount_rate_nodes) discount_factor = tf.math.exp(-rates * times) else: discount_factor = self._interpolator(times, self._times, self.discount_factor_nodes) return tf.identity(discount_factor, name=name or "discount_factor")
def __init__(self, valuation_date: types.DateTensor, market_data_dict: Dict[str, Any], config: Optional[Dict[str, Any]] = None, dtype: Optional[tf.DType] = None): """Market data constructor. ####Example ```python market_data_dict = { "Currency": { curve_index : {"date": DateTensor, "discount": tf.Tensor}, surface_id(curve_type): "to be specified", fixings: "to be specified"}, "Asset": "to be specified"} ``` Here `curve_index` refers to `curve_types.Index`. The user is expected to supply all necessary curves used for pricing. The pricing functions should decide which curve to use and how to map `RateIndexType` to `curve_types.Index`. Default mapping can be overridden via instrument configuration. Args: valuation_date: Valuation date. market_data_dict: Market data dictionary. config: Market data config. See `market_data_config` module description. Used to set up rate curve and volatility surface parameters. dtype: A `dtype` to use for float-like `Tensor`s. Default value: `tf.float64`. """ self._valuation_date = dateslib.convert_to_date_tensor(valuation_date) self._market_data_dict = market_data_dict self._config = config self._dtype = dtype or tf.float64
def cashflows(self, market: pmd.ProcessedMarketData, name: Optional[str] = None ) -> Tuple[types.DateTensor, types.FloatTensor]: """Returns cashflows for the fixed leg. Args: market: An instance of `ProcessedMarketData`. name: Python str. The name to give to the ops created by this function. Default value: `None` which maps to 'cashflows'. Returns: A tuple of two `Tensor`s of shape `batch_shape + [num_cashflows]` and containing the dates and the corresponding cashflows price for each stream based on the input market data. """ name = name or (self._name + "_cashflows") with tf.name_scope(name): valuation_date = dateslib.convert_to_date_tensor(market.date) future_cashflows = tf.cast(self._payment_dates >= valuation_date, dtype=self._dtype) # self._notional is of shape [batch_shape], so broadcasting is needed notional = tf.expand_dims(self._notional, axis=-1) # Cashflow present values. cashflows = notional * ( future_cashflows * self._daycount_fractions * self._coupon_rate) return self._payment_dates, cashflows
def price(self, valuation_date, market, model=None, pricing_context=None, name=None): """Returns the present value of the instrument on the valuation date. Args: valuation_date: A scalar `DateTensor` specifying the date on which valuation is being desired. market: A namedtuple of type `InterestRateMarket` which contains the necessary information for pricing the interest rate swap. model: Reserved for future use. pricing_context: Additional context relevant for pricing. name: Python str. The name to give to the ops created by this function. Default value: `None` which maps to 'price'. Returns: A Rank 1 `Tensor` of real type containing the modeled price of each IRS contract based on the input market data. """ name = name or (self._name + '_price') with tf.name_scope(name): valuation_date = dates.convert_to_date_tensor(valuation_date) pay_cf = self._pay_leg.price(valuation_date, market, model, pricing_context) receive_cf = self._receive_leg.price(valuation_date, market, model, pricing_context) return receive_cf - pay_cf
def __init__(self, swap, expiry_date=None, dtype=None, name=None): """Initialize a batch of European swaptions. Args: swap: An instance of `InterestRateSwap` specifying the interest rate swaps underlying the swaptions. The batch size of the swaptions being created would be the same as the batch size of the `swap`. expiry_date: An optional rank 1 `DateTensor` specifying the expiry dates for each swaption. The shape of the input should be the same as the batch size of the `swap` input. Default value: None in which case the option expity date is the same as the start date of each underlying swap. dtype: `tf.Dtype`. If supplied the dtype for the real variables or ops either supplied to the Swaption object or created by the Swaption object. Default value: None which maps to the default dtype inferred by TensorFlow. name: Python str. The name to give to the ops created by this class. Default value: `None` which maps to 'swaption'. """ self._name = name or 'swaption' with tf.name_scope(self._name): self._dtype = dtype self._expiry_date = dates.convert_to_date_tensor(expiry_date) self._swap = swap
def par_rate(self, valuation_date, market, model=None): """Returns the par swap rate for the swap.""" valuation_date = dates.convert_to_date_tensor(valuation_date) swap_annuity = self._annuity(valuation_date, market, model, False) float_pv = self._floating_leg.price(valuation_date, market, model) return float_pv / swap_annuity
def fixings(self, date: types.DateTensor, fixing_type: curve_types.RateIndexCurve, tenor: period_pb2.Period) -> types.FloatTensor: """Returns past fixings of the market rates at the specified dates.""" date = dateslib.convert_to_date_tensor(date) return tf.zeros(tf.shape(date.ordinal()), dtype=self._dtype, name="fixings")
def _refercence_rate_fn(t): # The input `t` is a real `Tensor` specifying the time from valuation. # We convert it into a `DateTensor` by first conversting it into the # corresponding ordinal (assuming ACT_365 convention). interpolation_ordinals = tf.cast( tf.round(t * 365.0 + valuation_date_ordinal), dtype=tf.int32) interpolation_dates = dateslib.convert_to_date_tensor( interpolation_ordinals) return reference_curve.discount_rate(interpolation_dates)
def price(self, valuation_date, market, model=None, pricing_context=None, name=None): """Returns the present value of the stream on the valuation date. Args: valuation_date: A scalar `DateTensor` specifying the date on which valuation is being desired. market: A namedtuple of type `InterestRateMarket` which contains the necessary information for pricing the cashflow stream. model: An optional input of type `InterestRateModelType` to specify which model to use for pricing. Default value: `None` in which case `NORMAL_RATE` model is used. pricing_context: An optional input to provide additional parameters (such as model parameters) relevant for pricing. name: Python str. The name to give to the ops created by this function. Default value: `None` which maps to 'price'. Returns: A Rank 1 `Tensor` of real type containing the modeled price of each stream contract based on the input market data. """ name = name or (self._name + '_price') with tf.name_scope(name): valuation_date = dates.convert_to_date_tensor(valuation_date) discount_curve = market.discount_curve past_fixing = rc.get_rate_index( market, self._start_date, rc.RateIndexType.SWAP, dtype=self._dtype) past_fixing = tf.repeat( tf.convert_to_tensor(past_fixing, dtype=self._dtype), self._num_cashflows) discount_factors = discount_curve.get_discount_factor(self._payment_dates) cms_rates = self._swap.par_rate(valuation_date, market, model) cms_rates = tf.where(self._daycount_fractions > 0., cms_rates, tf.zeros_like(cms_rates)) # If coupon end date is before the valuation date, the payment is in the # past. If valuation date is between coupon start date and coupon end # date, then the rate has been fixed but not paid. Otherwise the rate is # not fixed and should be read from the curve. cms_rates = tf.where( self._coupon_end_dates < valuation_date, tf.constant(0., dtype=self._dtype), tf.where(self._coupon_start_dates < valuation_date, past_fixing, cms_rates)) cms_rates = self._adjust_convexity( valuation_date, market, model, pricing_context, cms_rates, discount_factors) coupon_rate = self._coupon_multiplier * ( cms_rates + self._coupon_basis) cashflow_pvs = self._notional * ( self._daycount_fractions * coupon_rate * discount_factors) return tf.math.segment_sum(cashflow_pvs, self._contract_index)
def __init__(self, start_date, end_date, coupon_spec, dtype=None, name=None): """Initialize a batch of CMS cashflow streams. Args: start_date: A rank 1 `DateTensor` specifying the starting dates of the accrual of the first coupon of the cashflow stream. The shape of the input correspond to the numbercof streams being created. end_date: A rank 1 `DateTensor` specifying the end dates for accrual of the last coupon in each cashflow stream. The shape of the input should be the same as that of `start_date`. coupon_spec: A list of `CMSCouponSpecs` specifying the details of the coupon payment for the cashflow stream. The length of the list should be the same as the number of streams being created. Each coupon within the list must have the same daycount_convention and businessday_rule. dtype: `tf.Dtype`. If supplied the dtype for the real variables or ops either supplied to the FloatingCashflowStream object or created by the object. Default value: None which maps to the default dtype inferred by TensorFlow. name: Python str. The name to give to the ops created by this class. Default value: `None` which maps to 'floating_cashflow_stream'. """ super(CMSCashflowStream, self).__init__() self._name = name or 'cms_cashflow_stream' with tf.name_scope(self._name): self._start_date = dates.convert_to_date_tensor(start_date) self._end_date = dates.convert_to_date_tensor(end_date) self._batch_size = self._start_date.shape[0] self._first_coupon_date = None self._penultimate_coupon_date = None self._dtype = dtype self._setup(coupon_spec)
def ratecurve_from_discounting_function(discount_fn, dtype=None): """Returns `RateCurve` object using the supplied function for discounting. Args: discount_fn: A python callable which takes a `DateTensor` as an input and returns the corresponding discount factor as an output. dtype: `tf.Dtype`. Optional input specifying the dtype of the real tensors and ops. Returns: An object of class `RateCurveFromDiscountingFunction` which uses the supplied function for discounting. """ dtype = dtype or tf.constant(0.0).dtype pseudo_maturity_dates = dates.convert_to_date_tensor([(2020, 1, 1)]) pseudo_rates = tf.convert_to_tensor([0.0], dtype=dtype) pseudo_valuation_date = dates.convert_to_date_tensor((2020, 1, 1)) return RateCurveFromDiscountingFunction(pseudo_maturity_dates, pseudo_rates, pseudo_valuation_date, discount_fn, dtype)
def get_forward_rate(self, start_date, maturity_date, daycount_fraction=None): """Returns the simply accrued forward rate between [start_dt, maturity_dt]. Args: start_date: A `DateTensor` specifying the start of the accrual period for the forward rate. maturity_date: A `DateTensor` specifying the end of the accrual period for the forward rate. The shape of `maturity_date` must be the same as the shape of the `DateTensor` `start_date`. daycount_fraction: An optional `Tensor` of real dtype specifying the time between `start_date` and `maturity_date` in years computed using the forward rate's day count basis. The shape of the input should be the same as that of `start_date` and `maturity_date`. Default value: `None`, in which case the daycount fraction is computed using `ACTUAL_365` convention. Returns: A real tensor of same shape as the inputs containing the simply compounded forward rate. """ start_date = dates.convert_to_date_tensor(start_date) maturity_date = dates.convert_to_date_tensor(maturity_date) if daycount_fraction is None: daycount_fraction = dates.daycount_actual_365_fixed( start_date=start_date, end_date=maturity_date, dtype=self._dtype) else: daycount_fraction = tf.convert_to_tensor(daycount_fraction, self._dtype) dfstart = self.get_discount_factor(start_date) dfmaturity = self.get_discount_factor(maturity_date) return (dfstart / dfmaturity - 1.) / daycount_fraction
def discount_factor(self, interpolation_dates: types.DateTensor, name: Optional[str] = None): """Returns discount factors at `interpolation_dates`.""" interpolation_dates = dateslib.convert_to_date_tensor( interpolation_dates) times = self._get_time(interpolation_dates) if self._interpolate_rates: rates = self._interpolator(times, self._times, self.discount_rate_nodes) discount_factor = tf.math.exp(-rates * times) else: discount_factor = self._interpolator(times, self._times, self.discount_factor_nodes) return tf.identity(discount_factor, name=name or "discount_factor")
def __init__(self, market_data_dict: Dict[str, Any], dtype: Optional[tf.DType] = None): """Market data constructor. The dictionary must follow a format outlined in the doc: https://github.com/google/tf-quant-finance/tree/master/tf_quant_finance/experimental/pricing_platform/framework/market_data/market_data.pdf Args: market_data_dict: Market data dictionary. dtype: A `dtype` to use for float-like `Tensor`s. Default value: `tf.float64`. """ self._valuation_date = dateslib.convert_to_date_tensor( market_data_dict["reference_date"]) self._market_data_dict = market_data_dict self._dtype = dtype or tf.float64
def __init__(self, swap: interest_rate_swap.InterestRateSwap, expiry_date: Optional[Union[dateslib.DateTensor, List[List[int]]]], swaption_config: SwaptionConfig, batch_names: Optional[tf.Tensor] = None, dtype: Optional[types.Dtype] = None, name: Optional[str] = None): """Initialize a batch of European swaptions. Args: swap: An instance of `InterestRateSwap` specifying the interest rate swaps underlying the swaptions. The batch size of the swaptions being created would be the same as the batch size of the `swap`. expiry_date: An optional rank 1 `DateTensor` specifying the expiry dates for each swaption. The shape of the input should be the same as the batch size of the `swap` input. Default value: None in which case the option expity date is the same as the start date of each underlying swap. swaption_config: An input of type `SwaptionConfig` specifying the necessary information for swaption valuation. batch_names: A string `Tensor` of instrument names. Should be of shape `batch_shape + [2]` specying name and instrument type. This is useful when the `from_protos` method is used and the user needs to identify which instruments got batched together. dtype: `tf.Dtype`. If supplied the dtype for the real variables or ops either supplied to the Swaption object or created by the Swaption object. Default value: None which maps to the default dtype inferred by TensorFlow. name: Python str. The name to give to the ops created by this class. Default value: `None` which maps to 'swaption'. """ self._name = name or "swaption" with tf.name_scope(self._name): if batch_names is not None: self._names = tf.convert_to_tensor(batch_names, name="batch_names") else: self._names = None self._dtype = dtype or tf.float64 self._expiry_date = dateslib.convert_to_date_tensor(expiry_date) self._swap = swap self._config = swaption_config
def discount_rate(self, interpolation_dates: types.DateTensor, name: Optional[str] = None): """Returns interpolated rates at `interpolation_dates`.""" interpolation_dates = dateslib.convert_to_date_tensor( interpolation_dates) times = self._get_time(interpolation_dates) rates = self._interpolator(times, self._times, self.discount_rate_nodes) if self._interpolate_rates: rates = self._interpolator(times, self._times, self.discount_rate_nodes) else: discount_factor = self._interpolator(times, self._times, self.discount_factor_nodes) rates = -tf.math.divide_no_nan(tf.math.log(discount_factor), times) return tf.identity(rates, name=name or "discount_rate")
def forward_rates(self, market: pmd.ProcessedMarketData, name: Optional[str] = None ) -> Tuple[types.DateTensor, types.FloatTensor]: """Returns forward rates for the floating leg. Args: market: An instance of `ProcessedMarketData`. name: Python str. The name to give to the ops created by this function. Default value: `None` which maps to 'forward_rates'. Returns: A tuple of two `Tensor`s of shape `batch_shape + [num_cashflows]` containing the dates and the corresponding forward rates for each stream based on the input market data. """ name = name or (self._name + "_forward_rates") with tf.name_scope(name): reference_curve = get_discount_curve( self._reference_curve_type, market, self._reference_mask) valuation_date = dateslib.convert_to_date_tensor(market.date) past_fixing = _get_fixings( self._start_date, self._reference_curve_type, self._reset_frequency, self._reference_mask, market) forward_rates = reference_curve.forward_rate( self._accrual_start_date, self._accrual_end_date, day_count_fraction=self._daycount_fractions) forward_rates = tf.where(self._daycount_fractions > 0., forward_rates, tf.zeros_like(forward_rates)) # If coupon end date is before the valuation date, the payment is in the # past. If valuation date is between coupon start date and coupon end # date, then the rate has been fixed but not paid. Otherwise the rate is # not fixed and should be read from the curve. forward_rates = tf.where( self._coupon_end_dates < valuation_date, tf.constant(0, dtype=self._dtype), tf.where(self._coupon_start_dates >= valuation_date, forward_rates, tf.expand_dims(past_fixing, axis=-1))) return self._coupon_end_dates, forward_rates
def volatility_surface( self, currency: List[str], asset: List[str]) -> volatility_surface.VolatilitySurface: """The volatility surface object for the lsit of assets. Args: currency: A list of strings with currency names. asset: A list of strings with asset names. Returns: An instance of `VolatilitySurface`. """ dates = [] strikes = [] implied_vols = [] for cur, s in zip(currency, asset): if s not in self.supported_assets(cur): raise ValueError(f"No data for asset {s}") data_spot = self._market_data_dict["equities"][cur][s] if "volatility_surface" not in data_spot: raise ValueError( f"No volatility surface 'volatility_surface' for asset {s}" ) vol_surface = data_spot["volatility_surface"] vol_dates = dateslib.convert_to_date_tensor(vol_surface["dates"]) vol_strikes = tf.convert_to_tensor(vol_surface["strikes"], dtype=self._dtype, name="strikes") vols = tf.convert_to_tensor(vol_surface["implied_volatilities"], dtype=self._dtype, name="implied_volatilities") dates.append(vol_dates) strikes.append(vol_strikes) implied_vols.append(vols) dates = math.pad.pad_date_tensors(dates) dates = dateslib.DateTensor.stack(dates, axis=0) implied_vols = math.pad.pad_tensors(implied_vols) implied_vols = tf.stack(implied_vols, axis=0) strikes = math.pad.pad_tensors(strikes) strikes = tf.stack(strikes, axis=0) vol_surface = volatility_surface.VolatilitySurface( self.date, dates, strikes, implied_vols) return vol_surface
def volatility(self, strike: types.FloatTensor, expiry_dates: Optional[types.DateTensor] = None, expiry_times: Optional[types.FloatTensor] = None, term: Optional[types.Period] = None) -> types.FloatTensor: """Returns the interpolated volatility on a specified set of expiries. Args: strike: The strikes for which the interpolation is desired. expiry_dates: Optional input specifying the expiry dates for which interpolation is desired. The user should supply either `expiry_dates` or `expiry_times` for interpolation. expiry_times: Optional real `Tensor` containing the time to expiration for which interpolation is desired. The user should supply either `expiry_dates` or `expiry_times` for interpolation. term: Optional input specifying the term of the underlying rate for which the interpolation is desired. Relevant for interest rate implied volatility data. Returns: A `Tensor` of the same shape as `expiry` with the interpolated volatility from the volatility surface. Raises: ValueError is both `expiry_dates` and `expiry_times` are specified. """ del term if expiry_dates is not None and expiry_times is not None: raise ValueError( "Unexpected inputs: Both expiry_dates and expiry times " "are specified") if expiry_times is None: expiry_dates = dateslib.convert_to_date_tensor(expiry_dates) expiries = self._day_count_fn(start_date=self._valuation_date, end_date=expiry_dates, dtype=self._dtype) else: expiries = tf.convert_to_tensor(expiry_times, dtype=self._dtype) strike = tf.convert_to_tensor(strike, dtype=self._dtype, name="strike") return self._interpolator(expiries, strike)
def price(self, valuation_date, market, model=None, pricing_context=None, name=None): """Returns the present value of the Cap/Floor on the valuation date. Args: valuation_date: A scalar `DateTensor` specifying the date on which valuation is being desired. market: A namedtuple of type `InterestRateMarket` which contains the necessary information for pricing the Cap/Floor. model: An optional input of type `InterestRateModelType` to specify which model to use for pricing. Default value: `None` in which case `LOGNORMAL_RATE` model is used. pricing_context: An optional input to provide additional parameters (such as model parameters) relevant for pricing. name: Python str. The name to give to the ops created by this function. Default value: `None` which maps to `"price"`. Returns: A Rank 1 `Tensor` of real type containing the modeled price of each cap (or floor) based on the input market data. Raises: ValueError: If an unsupported model is supplied to the function. """ model = model or rc.InterestRateModelType.LOGNORMAL_RATE name = name or (self._name + '_price') with tf.name_scope(name): valuation_date = dates.convert_to_date_tensor(valuation_date) if model == rc.InterestRateModelType.LOGNORMAL_RATE: caplet_prices = self._price_lognormal_rate( valuation_date, market, pricing_context) else: raise ValueError(f'Unsupported model {model}.') return tf.math.segment_sum(caplet_prices, self._contract_index)
def __init__(self, valuation_date: types.DateTensor, market_data_dict: Dict[str, Any], config: Optional[Dict[str, Any]] = None, dtype: Optional[tf.DType] = None): """Market data constructor. The dictionary must follow a format outlined in the doc: https://github.com/google/tf-quant-finance/tree/master/tf_quant_finance/experimental/pricing_platform/framework/market_data/market_data.pdf Args: valuation_date: Valuation date. market_data_dict: Market data dictionary. config: Market data config. See `market_data_config` module description. Used to set up rate curve and volatility surface parameters. dtype: A `dtype` to use for float-like `Tensor`s. Default value: `tf.float64`. """ self._valuation_date = dateslib.convert_to_date_tensor(valuation_date) self._market_data_dict = market_data_dict self._config = config self._dtype = dtype or tf.float64
def price(self, market: pmd.ProcessedMarketData, name: Optional[str] = None): """Returns the present value of the swaption on the valuation date. Args: market: A instance of type `ProcessedMarketData` which contains the necessary information for pricing the swaption. name: Python str. The name to give to the ops created by this function. Default value: `None` which maps to 'price'. Returns: A Rank `Tensor` of shape `batch_shape` containing the modeled price of each Swaption contract based on the input market data. Raises: ValueError: If an unsupported model is supplied to the function. """ model = (self._config.model or models.InterestRateModelType.HULL_WHITE_ONE_FACTOR) name = name or (self._name + "_price") with tf.name_scope(name): valuation_date = dateslib.convert_to_date_tensor(market.date) strike = self._swap.fixed_rate() expiry_time = dateslib.daycount_actual_365_fixed( start_date=valuation_date, end_date=self._expiry_date, dtype=self._dtype) if model == models.InterestRateModelType.HULL_WHITE_ONE_FACTOR: option_value = self._price_hull_white_1_factor( valuation_date, market, strike, expiry_time) else: raise ValueError("Unsupported model.") return option_value
def volatility(self, expiry: types.DateTensor, strike: types.FloatTensor, term: Optional[types.Period] = None) -> types.FloatTensor: """Returns the interpolated volatility on a specified set of expiries. Args: expiry: The expiry dates for which the interpolation is desired. strike: The strikes for which the interpolation is desired. term: Optional input specifiying the term of the underlying rate for which the interpolation is desired. Relevant for interest rate implied volatility data. Returns: A `Tensor` of the same shape as `expiry` with the interpolated volatility from the volatility surface. """ del term expiry = dateslib.convert_to_date_tensor(expiry) expiries = self._day_count_fn(start_date=self._valuation_date, end_date=expiry, dtype=self._dtype) strike = tf.convert_to_tensor(strike, dtype=self._dtype, name="strike") return self._interpolator.interpolate(expiries, strike)
def __init__(self, contract_start_date, contract_end_date, daycount_convention=None, averaging_type=None, contract_unit=1., holiday_calendar=None, dtype=None, name=None): """Initialize the Overnight index futures object. Args: contract_start_date: A Rank 1 `DateTensor` specifying the start dates of the reference period (or delivery period) of each futures contract. The published overnight index during the reference period determines the final settlement price of the futures contract. contract_end_date: A Rank 1 `DateTensor` specifying the ending dates of the reference period (or delivery period) of each futures contract. daycount_convention: An optional scalar `DayCountConvention` corresponding to the day count convention for the underlying rate for each contract. Default value: None in which case each the day count convention equal to DayCountConvention.ACTUAL_360 is used. averaging_type: An optional `AverageType` corresponding to how the final settlement rate is computed from daily rates. Default value: None, in which case `AverageType.COMPOUNDING` is used. contract_unit: An optional scalar or Rank 1 `Tensor` of real dtype specifying the notional amount for the contract. If the notional is entered as a scalar, it is assumed that all of the contracts have a notional equal to the input value. Default value: 1.0 holiday_calendar: An instance of `dates.HolidayCalenday` to specify weekends and holidays. Default value: None in which case a holiday calendar would be created with Saturday and Sunday being the holidays. dtype: `tf.Dtype`. If supplied the dtype for the real variables or ops either supplied to the EurodollarFuture object or created by the EurodollarFuture object. Default value: None which maps to the default dtype inferred by TensorFlow. name: Python str. The name to give to the ops created by this class. Default value: `None` which maps to 'eurodollar_future'. """ self._name = name or 'overnight_rate_futures' with tf.compat.v2.name_scope(self._name): self._contract_unit = tf.convert_to_tensor(contract_unit, dtype=dtype) self._dtype = dtype if dtype else self._contract_unit.dtype self._start_date = dates.convert_to_date_tensor( contract_start_date) self._end_date = dates.convert_to_date_tensor(contract_end_date) self._batch_size = self._start_date.shape[0] if daycount_convention is None: daycount_convention = rc.DayCountConvention.ACTUAL_360 if averaging_type is None: averaging_type = rc.AverageType.COMPOUNDING if holiday_calendar is None: holiday_calendar = dates.create_holiday_calendar( weekend_mask=dates.WeekendMask.SATURDAY_SUNDAY) self._daycount_convention = daycount_convention self._averaging_type = averaging_type self._holiday_calendar = holiday_calendar self._rate_tenor = dates.day() self._setup()
def __init__(self, start_date: Union[dateslib.DateTensor, List[List[int]]], maturity_date: Union[dateslib.DateTensor, List[List[int]]], pay_leg: Union[coupon_specs.FixedCouponSpecs, coupon_specs.FloatCouponSpecs], receive_leg: Union[coupon_specs.FixedCouponSpecs, coupon_specs.FloatCouponSpecs], pay_leg_schedule_fn=None, pay_leg_schedule=None, receive_leg_schedule_fn=None, receive_leg_schedule=None, config: Union[InterestRateSwapConfig, Dict[str, Any]] = None, batch_names: Optional[tf.Tensor] = None, dtype: Optional[types.Dtype] = None, name: Optional[str] = None): """Initializes a batch of IRS contracts. Args: start_date: A `DateTensor` of `batch_shape` specifying the dates for the inception (start of the accrual) of the swap contracts. `batch_shape` corresponds to the number of instruments being created. maturity_date: A `DateTensor` broadcastable with `start_date` specifying the maturity dates for each contract. pay_leg: An instance of `FixedCouponSpecs` or `FloatCouponSpecs` specifying the coupon payments for the payment leg of the swap. receive_leg: An instance of `FixedCouponSpecs` or `FloatCouponSpecs` specifying the coupon payments for the receiving leg of the swap. pay_leg_schedule_fn: A callable that accepts `start_date`, `end_date`, `coupon_frequency`, `settlement_days`, `first_coupon_date`, and `penultimate_coupon_date` as `Tensor`s and returns coupon payment days. Constructs schedule for the pay leg of the swap. Default value: `None`. pay_leg_schedule: A `DateTensor` of coupon payment dates for the pay leg. receive_leg_schedule_fn: A callable that accepts `start_date`, `end_date`, `coupon_frequency`, `settlement_days`, `first_coupon_date`, and `penultimate_coupon_date` as `Tensor`s and returns coupon payment days. Constructs schedule for the receive leg of the swap. Default value: `None`. receive_leg_schedule: A `DateTensor` of coupon payment dates for the receive leg. config: Optional `InterestRateSwapConfig` or a dictionary. If dictionary, then the keys should be the same as the field names of `InterestRateSwapConfig`. batch_names: A string `Tensor` of instrument names. Should be of shape `batch_shape + [2]` specying name and instrument type. This is useful when the `from_protos` method is used and the user needs to identify which instruments got batched together. dtype: `tf.Dtype` of the input and output real `Tensor`s. Default value: None which maps to the default dtype inferred by TensorFlow. name: Python str. The name to give to the ops created by this class. Default value: `None` which maps to 'interest_rate_swap'. """ self._name = name or "interest_rate_swap" with tf.name_scope(self._name): if batch_names is not None: self._names = tf.convert_to_tensor(batch_names, name="batch_names") else: self._names = None self._dtype = dtype or tf.float64 self._model = None # Ignore self._config = _process_config(config) if isinstance(pay_leg, dict): self._discount_curve_type = pay_leg["discount_curve_type"] self._start_date = start_date else: currencies = cashflow_streams.to_list(pay_leg.currency) self._discount_curve_type = [] if pay_leg.currency != receive_leg.currency: raise ValueError( "Pay and receive legs should have the same currency") for currency in currencies: if currency in self._config.discounting_curve: discount_curve = self._config.discounting_curve[ currency] self._discount_curve_type.append(discount_curve) else: # Default discounting is the risk free curve risk_free = curve_types_lib.RiskFreeCurve( currency=currency) self._discount_curve_type.append(risk_free) if isinstance(start_date, tf.Tensor): self._start_date = dateslib.dates_from_tensor(start_date) else: self._start_date = dateslib.convert_to_date_tensor(start_date) if isinstance(start_date, tf.Tensor): self._maturity_date = dateslib.dates_from_tensor(maturity_date) else: self._maturity_date = dateslib.convert_to_date_tensor( maturity_date) self._pay_leg_schedule_fn = pay_leg_schedule_fn self._receive_leg_schedule_fn = receive_leg_schedule_fn self._pay_leg_schedule = pay_leg_schedule self._receive_leg_schedule = receive_leg_schedule self._pay_leg = _setup_leg(self._start_date, self._maturity_date, self._discount_curve_type, pay_leg, self._pay_leg_schedule_fn, self._pay_leg_schedule) self._receive_leg = _setup_leg(self._start_date, self._maturity_date, self._discount_curve_type, receive_leg, self._receive_leg_schedule_fn, self._receive_leg_schedule) self._batch_shape = self._pay_leg.batch_shape
def __init__(self, start_date: Union[dateslib.DateTensor, List[List[int]]], maturity_date: Union[dateslib.DateTensor, List[List[int]]], pay_leg: Union[coupon_specs.FixedCouponSpecs, coupon_specs.FloatCouponSpecs], receive_leg: Union[coupon_specs.FixedCouponSpecs, coupon_specs.FloatCouponSpecs], swap_config: InterestRateSwapConfig = None, batch_names: Optional[tf.Tensor] = None, dtype: Optional[types.Dtype] = None, name: Optional[str] = None): """Initializes a batch of IRS contracts. Args: start_date: A `DateTensor` of `batch_shape` specifying the dates for the inception (start of the accrual) of the swap contracts. `batch_shape` corresponds to the number of instruments being created. maturity_date: A `DateTensor` broadcastable with `start_date` specifying the maturity dates for each contract. pay_leg: An instance of `FixedCouponSpecs` or `FloatCouponSpecs` specifying the coupon payments for the payment leg of the swap. receive_leg: An instance of `FixedCouponSpecs` or `FloatCouponSpecs` specifying the coupon payments for the receiving leg of the swap. swap_config: Optional `InterestRateSwapConfig`. batch_names: A string `Tensor` of instrument names. Should be of shape `batch_shape + [2]` specying name and instrument type. This is useful when the `from_protos` method is used and the user needs to identify which instruments got batched together. dtype: `tf.Dtype` of the input and output real `Tensor`s. Default value: None which maps to the default dtype inferred by TensorFlow. name: Python str. The name to give to the ops created by this class. Default value: `None` which maps to 'interest_rate_swap'. """ self._name = name or "interest_rate_swap" with tf.name_scope(self._name): if batch_names is not None: self._names = tf.convert_to_tensor(batch_names, name="batch_names") else: self._names = None self._dtype = dtype or tf.float64 self._model = None # Ignore currency = pay_leg.currency if pay_leg.currency != receive_leg.currency: raise ValueError( "Pay and receive legs should have the same currency") if swap_config is not None: try: self._discount_curve_type = swap_config.discounting_index[ currency] except KeyError: self._discount_curve_type = curve_types.CurveType( currency=currency, index_type=curve_types.Index.OIS) else: self._discount_curve_type = curve_types.CurveType( currency=currency, index_type=curve_types.Index.OIS) self._start_date = dateslib.convert_to_date_tensor(start_date) self._maturity_date = dateslib.convert_to_date_tensor( maturity_date) self._pay_leg = self._setup_leg(pay_leg) self._receive_leg = self._setup_leg(receive_leg) if self._receive_leg.batch_shape != self._pay_leg.batch_shape: raise ValueError( "Batch shapes of pay and receive legs should be the " "same.") self._batch_shape = self._pay_leg.batch_shape
def get_discount_factor(self, interpolation_dates): """Returns discount factors at `interpolation_dates`.""" idates = dates.convert_to_date_tensor(interpolation_dates) times = self._get_time(idates) return tf.math.exp(-self.get_rates(idates) * times)