def test_basisswap_pv_zero_if_onecurve_termstructure(): notl = 1e8 dt_start = dt_val leg6m = IborLeg.from_tenor(dt_start, length, frequency=6, notional=notl) leg3m = IborLeg.from_tenor(dt_start, length, frequency=3, notional=-notl) basis_swap = Swap(leg3m, leg6m) mkt_1crv = RatesTermStructure(dt_val, {curr: {'discount': crv_disc}}) pv_6m_1crv = present_value(leg6m, mkt_1crv, curr) pv_3m_1crv = present_value(leg3m, mkt_1crv, curr) pv_1crv = present_value(basis_swap, mkt_1crv, curr) assert np.isclose(pv_6m_1crv, notl) assert np.isclose(pv_3m_1crv, -notl) assert np.isclose(pv_1crv, 0.0) spread = 0.005 # 5 basis point spread crv_6m = DiscountCurveWithNodes(dt_val, node_dates, node_rates + spread, interpolator=interpolator, extrapolate=('clamped', 'natural')) mkt_2crv = RatesTermStructure(dt_val, {curr: { 'discount': crv_disc, 6: crv_6m }}) pv_2crv = present_value(basis_swap, mkt_2crv, curr) assert not np.isclose(pv_2crv, 0.0)
def test_iborleg(): """Test equality of various construction calls""" float_leg = IborLeg.from_tenor(dt_settlement=dt_settle, tenor=length, frequency=frqncy, rate=fixed_rate, notional=notional, fixing_lag=2) # from_frame annuity_from_frame = Annuity.from_frame(float_leg.frame) assert annuity_from_frame != float_leg fixed_leg_from_frame = FixedLeg.from_frame(float_leg.frame) assert fixed_leg_from_frame != float_leg ibor_leg_from_frame = IborLeg.from_frame(float_leg.frame) assert ibor_leg_from_frame == float_leg # init annuity_init = Annuity(float_leg.frame) assert annuity_init != float_leg fixed_leg_init = FixedLeg(float_leg.frame) assert annuity_init != float_leg ibor_leg_init = IborLeg(float_leg.frame) assert ibor_leg_init == float_leg
def test_present_value_vanilla_ibor_leg_at_fixing_date_equals_notional(): """Confirm spot starting Iborleg with Notional Exchange is worth par This is a canonical result of funding at ibor. Though there are two curves, both discount and ibor curves are equal. """ # Constant Curves zero_spread = 0.0 crv_ibor_no_spread = ConstantDiscountRateCurve(dt_valuation=dt_val, zero_rate=rate_discount + zero_spread, daycount_conv='30360', currency=curr) curves = {curr: {'discount': crv_discount, frqncy: crv_ibor_no_spread}} two_constant_curves = RatesTermStructure.from_curve_map(dt_val, curves) spot_starting = IborLeg.from_tenor(dt_settlement=dt_val, tenor=length, frequency=frqncy, rate=np.nan, notional=-notional, fixing_lag=0) pv_flt = present_value(spot_starting, two_constant_curves, curr) assert np.isclose(pv_flt, -notional) # Nodal Curves assert np.isclose(present_value(spot_starting, nodal_rates_market, curr), -notional)
def strip_of_swaps(dt_settlement, currency, tenor, maturities, rates): """Strip / List of Swaps of increasing length and a single currency and tenor These strips are used to calibrate nodes in discount and forward curves. If we are interested in pricing derivatives that depends on rates of two different frequencies (eg 3M & 12M), we will need one strip per frequency. Curve TODO Business date treatment TODO Add proper conventions """ idx = np.arange(len(maturities)) fixed_legs = [ FixedLeg.from_tenor(dt_settlement, maturities[i], tenor, rates[i], currency=currency) for i in idx ] float_legs = [ IborLeg.from_tenor(dt_settlement, maturities[i], tenor, notional=-1., currency=currency) for i in idx ] swaps = [VanillaSwap(fixed_legs[i], float_legs[i]) for i in idx] return swaps
def test_fixing_lag(): """Ensure lag of 2 provides minimum of 2 days lag. This is under default business day adjustment. """ # Todo - what is the default business day adjustment??? leg_no_lag = IborLeg.from_tenor(dt_settlement=dt_settle, tenor=length, frequency=frqncy, rate=fixed_rate, notional=-1 * notional, fixing_lag=0) leg_lag = IborLeg.from_tenor(dt_settlement=dt_settle, tenor=length, frequency=frqncy, rate=fixed_rate, notional=-1 * notional, fixing_lag=2) assert np.all(leg_lag.frame['fixing'] > leg_no_lag.frame['fixing'] + pd.Timedelta(days=1))
def test_swap(): fixed_leg = FixedLeg.from_tenor(dt_settlement=dt_settle, tenor=length, frequency=frqncy, rate=fixed_rate, notional=notional) float_leg = IborLeg.from_tenor(dt_settlement=dt_settle, tenor=length, frequency=frqncy, rate=fixed_rate, notional=-1 * notional, fixing_lag=2) swap = Swap(fixed_leg, float_leg) assert swap.leg_receive == fixed_leg assert swap.leg_pay == float_leg
def test_vanilla_swap(): fixed_leg = FixedLeg.from_tenor(dt_settlement=dt_settle, tenor=length, frequency=frqncy, rate=fixed_rate, notional=notional, currency='EUR') float_leg = IborLeg.from_tenor(dt_settlement=dt_settle, tenor=length, frequency=frqncy, rate=fixed_rate, notional=-1 * notional, currency='EUR') swap = VanillaSwap(fixed_leg, float_leg) assert swap.leg_receive == fixed_leg assert swap.leg_pay == float_leg
def par_rate(contract, market): df_fixed = contract.leg_fixed.frame.copy() df_fixed.rate = 1.0 df_fixed.notional *= -1 annuity = FixedLeg.from_frame(df_fixed, notl_exchange=False) df_float = contract.leg_float.frame.copy() floating_no_xch = IborLeg.from_frame(df_float, notl_exchange=False) ccy = contract.leg_fixed.currency assert ccy == contract.leg_float.currency pv_fix = present_value(annuity, market, ccy) pv_flt = present_value(floating_no_xch, market, ccy) return pv_flt / pv_fix
def test_basisswap_pv_zero_if_onecurve_termstructure(): notl = 1e8 dt_start = dt_val leg6m = IborLeg.from_tenor(dt_start, length, frequency=6, notional=notl) leg3m = IborLeg.from_tenor(dt_start, length, frequency=3, notional=-notl) basis_swap = Swap(leg3m, leg6m) mkt_1crv = RatesTermStructure(dt_val, {curr: {'discount': crv_disc}}) pv_6m_1crv = present_value(leg6m, mkt_1crv, curr) pv_3m_1crv = present_value(leg3m, mkt_1crv, curr) pv_1crv = present_value(basis_swap, mkt_1crv, curr) assert np.isclose(pv_6m_1crv, notl) assert np.isclose(pv_3m_1crv, -notl) assert np.isclose(pv_1crv, 0.0) spread = 0.005 # 5 basis point spread crv_6m = DiscountCurveWithNodes(dt_val, node_dates, node_rates + spread, interpolator=interpolator, extrapolate=('clamped', 'natural')) mkt_2crv = RatesTermStructure(dt_val, {curr: {'discount': crv_disc, 6: crv_6m}}) pv_2crv = present_value(basis_swap, mkt_2crv, curr) assert not np.isclose(pv_2crv, 0.0)
def test_present_value_of_swap_after_expiry(): dt_settle = dt_val - pd.Timedelta(days=1000) fixed_leg = FixedLeg.from_tenor(dt_settlement=dt_settle, tenor=length, frequency=frqncy, rate=fixed_rate, notional=notional) float_leg = IborLeg.from_tenor(dt_settlement=dt_settle, tenor=length, frequency=frqncy, rate=fixed_rate, notional=-notional, fixing_lag=0) pv_fix = present_value(fixed_leg, simple_rates_market, curr) assert np.isclose(pv_fix, 0.0) pv_flt = present_value(float_leg, simple_rates_market, curr) assert np.isclose(pv_flt, 0.0)
def test_present_value_vanilla_ibor_leg_at_fixing_date_equals_notional(): """Confirm spot starting Iborleg with Notional Exchange is worth par This is a canonical result of funding at ibor. Though there are two curves, both discount and ibor curves are equal. """ # Constant Curves zero_spread = 0.0 crv_ibor_no_spread = ConstantDiscountRateCurve( dt_valuation=dt_val, zero_rate=rate_discount + zero_spread, daycount_conv='30360', currency=curr) curves = {curr: {'discount': crv_discount, frqncy: crv_ibor_no_spread}} two_constant_curves = RatesTermStructure.from_curve_map(dt_val, curves) spot_starting = IborLeg.from_tenor(dt_settlement=dt_val, tenor=length, frequency=frqncy, rate=np.nan, notional=-notional, fixing_lag=0) pv_flt = present_value(spot_starting, two_constant_curves, curr) assert np.isclose(pv_flt, -notional) # Nodal Curves assert np.isclose(present_value(spot_starting,nodal_rates_market, curr), -notional)
fixed_leg.frame.currency.iloc[0]: { 'discount': crv_discount, frqncy: crv_ibor } } simple_rates_market = RatesTermStructure.from_curve_map(dt_val, curve_map) # 2. Test IborLeg # Hack up what the frame might look like df_fixed = fixed_leg.frame df_float = df_fixed.copy() df_float.type = 'IBOR' df_float['fixing'] = df_fixed.start df_float['frequency'] = frqncy df_float.notional *= -1 float_leg = IborLeg.from_frame(df_float) # Calculate Forward Rates for each ibor cash flow forwards = ibor_rate(float_leg, simple_rates_market) # 3. Test VanillaSwap swap = VanillaSwap(fixed_leg, float_leg) # 4. Test pricing print('pv fixed_leg = {}'.format( present_value(fixed_leg, simple_rates_market, curr))) print('pv float_leg = {}'.format( present_value(float_leg, simple_rates_market, curr))) print('pv swap = {}'.format(present_value(swap, simple_rates_market, curr))) print('forward rates = {}'.format(forwards))
notional = 100 dcc = '30360' fixed_legs, float_legs, swaps = [], [], [] for i in mkt_ids: fixed_legs.append( FixedLeg.from_tenor(dt_settle, durations[i], frqncy, fixed_rates[i], notional=notional, currency=curr)) float_legs.append( IborLeg.from_tenor(dt_settle, durations[i], frqncy, notional=-1 * notional, currency=curr)) swaps.append(VanillaSwap(fixed_legs[i], float_legs[i])) market_portfolio = Portfolio.of_trades(swaps) # 3. Create Market. Specify number of curves to use, and the interpolators interpolator = CubicSplineWithNodeSens # CubicSplineWithNodeSens, PiecewiseLinear n_curves = 2 accrual_fn = daycounter(dcc) node_dates = [] for i in range(n_contracts): # final pay date of each swap node_dates.append(fixed_legs[i].frame.pay.iloc[-1]) node_dates = pd.Series(node_dates)
length = 24 # months frqncy = 6 # months fixed_rate = 0.03 notional = 100 curr = "USD" payment_lag = 2 # days # 1. Create a Vanilla Swap fixed_leg = FixedLeg.from_tenor(dt_settlement=dt_settle, tenor=length, frequency=frqncy, rate=fixed_rate, notional=notional) # Note that fixed rates are provided to IborLeg. In pricing, only those in the # past will be used. Others will be replaced by their Forward rates. float_leg = IborLeg.from_tenor(dt_settlement=dt_settle, tenor=length, frequency=frqncy, rate=fixed_rate, notional=-notional, fixing_lag=0) swap = VanillaSwap(fixed_leg, float_leg) # 2. Create Market with Ibor and Discount Curves - both with Constant Rates rate_discount = 0.05 crv_discount = ConstantDiscountRateCurve( dt_valuation=dt_val, zero_rate=rate_discount, daycount_conv='30360', currency=curr) spread = 0.002 crv_disc = ConstantDiscountRateCurve( # Dummy IBOR Curve dt_valuation=dt_val, zero_rate=rate_discount + spread, daycount_conv='30360', currency=curr)
crv_ibor = ConstantDiscountRateCurve( # Dummy IBOR Curve dt_valuation=dt_val, zero_rate=rate_discount + spread, daycount_conv='30360', currency=curr) curve_map = {fixed_leg.frame.currency.iloc[0]: {'discount': crv_discount, frqncy: crv_ibor}} simple_rates_market = RatesTermStructure.from_curve_map(dt_val, curve_map) # 2. Test IborLeg # Hack up what the frame might look like df_fixed = fixed_leg.frame df_float = df_fixed.copy() df_float.type = 'IBOR' df_float['fixing'] = df_fixed.start df_float['frequency'] = frqncy df_float.notional *= -1 float_leg = IborLeg.from_frame(df_float) # Calculate Forward Rates for each ibor cash flow forwards = ibor_rate(float_leg, simple_rates_market) # 3. Test VanillaSwap swap = VanillaSwap(fixed_leg, float_leg) # 4. Test pricing print('pv fixed_leg = {}'.format(present_value(fixed_leg, simple_rates_market, curr))) print('pv float_leg = {}'.format(present_value(float_leg, simple_rates_market, curr))) print('pv swap = {}'.format(present_value(swap, simple_rates_market, curr))) print('forward rates = {}'.format(forwards)) print('swap rate = {}'.format(par_rate(swap, simple_rates_market)))
fixed_rate = 0.03 notional = 100 curr = "USD" payment_lag = 2 # days # 1. Create a Vanilla Swap fixed_leg = FixedLeg.from_tenor(dt_settlement=dt_settle, tenor=length, frequency=frqncy, rate=fixed_rate, notional=notional) # Note that fixed rates are provided to IborLeg. In pricing, only those in the # past will be used. Others will be replaced by their Forward rates. float_leg = IborLeg.from_tenor(dt_settlement=dt_settle, tenor=length, frequency=frqncy, rate=fixed_rate, notional=-notional, fixing_lag=0) swap = VanillaSwap(fixed_leg, float_leg) # 2. Create Market with Ibor and Discount Curves - both with Constant Rates rate_discount = 0.05 crv_discount = ConstantDiscountRateCurve(dt_valuation=dt_val, zero_rate=rate_discount, daycount_conv='30360', currency=curr) spread = 0.002 crv_disc = ConstantDiscountRateCurve( # Dummy IBOR Curve dt_valuation=dt_val,