Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 31

Pricing Inverse Floaters with Replication in Python

Recommended resources

Introduction

In our last lesson, we established the core principle for valuing an inverse floater: replication. We derived the price by creating a synthetic portfolio of a leveraged long position in a fixed-rate bond and a short position in a floating-rate note. Specifically, we saw that for an inverse floater with coupon , its price is given by:

Today, we will transition from mathematical derivation to practical application. Your goal for this lesson is to implement this replication-based pricing model in Python. We will build a function that takes the parameters of an inverse floater and a given zero-coupon yield curve, and returns its arbitrage-free price. This will involve creating a modular solution by reusing functions to price the simpler, constituent bonds, a common practice in quantitative finance programming.


Step 1: Building the Component Pricers

Before we can price the inverse floater, we need reliable functions to price its components: the fixed-rate bond and the floating-rate note.

A. Fixed-Rate Bond Pricer

From Module 2, you'll recall that a fixed-rate bond is priced by discounting its cash flows using the spot rates from the zero-coupon yield curve (ZCYC). We will implement this in a Python function.

For this implementation, we will make a few structural choices:

  • The ZCYC will be passed as a Python dictionary, mapping maturities (in years) to their corresponding annualized spot rates.
  • To match common market convention (and the example from our previous lesson), we will assume the spot rates provided are Bond Equivalent Yields (BEY), meaning they are semi-annually compounded. The discounting formula for a cash flow at time using a spot rate is therefore .
  • Our function will rely on the numpy library for efficient numerical operations.

Here is the implementation for the fixed-rate bond pricer.

import numpy as np

def price_fixed_rate_bond_from_zcyc(face_value, coupon_rate, maturity, frequency, zcyc):
    """
    Prices a fixed-rate bond using a dictionary of zero-coupon rates (spot curve).

    Args:
        face_value (float): The principal amount of the bond.
        coupon_rate (float): The annual coupon rate of the bond.
        maturity (float): The bond's maturity in years.
        frequency (int): The number of coupon payments per year.
        zcyc (dict): A dictionary of {maturity: spot_rate} representing the BEY spot curve.

    Returns:
        float: The price of the bond.
    """



    # Generate an array of time points for each cash flow
    # np.arange(start, stop, step)
    payment_times = np.arange(1/frequency, maturity + 1/frequency, 1/frequency)




    # Calculate the fixed coupon payment amount
    coupon_payment = face_value * coupon_rate / frequency
    



    # Calculate the present value of all cash flows
    price = 0
    for t in payment_times:



        # For this example, we assume the zcyc has a rate for every payment time.
        # In a real-world scenario, you would interpolate the zcyc first.
        spot_rate = zcyc[t]
        



        # Discount factor using semi-annual compounding (BEY convention)
        df = 1 / (1 + spot_rate / 2)**(2 * t)
        



        # The final payment includes the principal
        if t == maturity:
            cash_flow = coupon_payment + face_value
        else:
            cash_flow = coupon_payment
            
        price += cash_flow * df
        
    return price

B. Floating-Rate Note Pricer

As we established in Module 6, pricing a standard floater is much simpler. On any coupon reset date, its value is par. Our Python function will reflect this elegant simplification.

def price_floater(face_value):
    """
    Prices a standard floating-rate note on a coupon reset date.

    Args:
        face_value (float): The principal amount of the floater.

    Returns:
        float: The price of the floater, which is its face value.
    """



    # On a reset date, a standard floater is always valued at par.
    return face_value

Step 2: Implementing the Replication-Based Pricer

With the building blocks in place, we can now construct the main function for pricing the inverse floater. This function will orchestrate the pricing of the components according to the replication formula.

The function price_inverse_floater will take the inverse floater's parameters, including its leverage factor , and use our component pricers to calculate the final price.

A key step inside this function is determining the coupon rate c of the underlying fixed-rate bond from the inverse floater's fixed component K and its leverage M, using the relationship we derived: .

def price_inverse_floater(
    inv_face_value, 
    k_rate, 
    maturity, 
    frequency, 
    leverage_factor, 
    zcyc
):
    """
    Prices an inverse floater using the replication method.

    Args:
        inv_face_value (float): The face value of the inverse floater.
        k_rate (float): The fixed rate 'K' in the 'K - M*r' coupon formula.
        maturity (float): The maturity in years.
        frequency (int): The coupon payment frequency per year.
        leverage_factor (M): The leverage multiplier 'M' in the coupon formula.
        zcyc (dict): The zero-coupon yield curve (BEY).

    Returns:
        float: The arbitrage-free price of the inverse floater.
    """



    # 1. Determine the parameters of the underlying fixed-rate bond component.
    # The coupon rate 'c' of the fixed bond is derived from 'K' and 'M'.
    fixed_bond_coupon = k_rate / (leverage_factor + 1)
    



    # We use a unit par value for pricing the components to maintain clarity.
    unit_par = 100.0




    # 2. Price the unit fixed-rate bond.
    price_fixed_unit = price_fixed_rate_bond_from_zcyc(
        face_value=unit_par,
        coupon_rate=fixed_bond_coupon,
        maturity=maturity,
        frequency=frequency,
        zcyc=zcyc
    )




    # 3. Price the unit floater.
    price_floater_unit = price_floater(face_value=unit_par)
    



    # 4. Apply the replication formula to get the price of a unit inverse floater.
    # P_inv = (M+1)*P_fixed - M*P_floater
    price_inverse_unit = (leverage_factor + 1) * price_fixed_unit - leverage_factor * price_floater_unit
    



    # 5. Scale the unit price to the actual face value of the inverse floater.
    final_price = (price_inverse_unit / unit_par) * inv_face_value
    
    print(f"--- Inverse Floater Pricing Breakdown ---")
    print(f"Underlying Fixed Coupon (c): {fixed_bond_coupon:.4%}")
    print(f"Price of Unit Fixed Bond (Par={unit_par}): {price_fixed_unit:.4f}")
    print(f"Price of Unit Floater (Par={unit_par}): {price_floater_unit:.4f}")
    print(f"Price of Unit Inverse Floater: {price_inverse_unit:.4f}")
    print(f"----------------------------------------")
    
    return final_price


Step 3: A Worked Example in Python

Let's test our implementation using the same example from the previous lesson, which originated from the NYU Stern notes.

  • Instrument: A 2-year inverse floater with a $100 par value, paying a semi-annual coupon of 11% minus the floating rate.
  • Parameters:
    • inv_face_value = 100
    • k_rate = 0.11
    • maturity = 2 years
    • frequency = 2 (semi-annual)
    • This is an "even split," so leverage_factor (M) = 1.
  • Market Data (ZCYC):
    • = 5.54%
    • = 5.45%
    • = 5.47%
    • = 5.50%

Now, let's run the code with these inputs.




# --- INPUTS ---




# 1. ZCYC from the market (from previous lesson's example)
zcyc_data = {
    0.5: 0.0554,
    1.0: 0.0545,
    1.5: 0.0547,
    2.0: 0.0550
}




# 2. Inverse Floater Parameters
face_value = 100.0
coupon_k = 0.11
maturity_yrs = 2.0
pmt_frequency = 2
leverage = 1.0




# --- CALCULATION ---




# Price the inverse floater using our replication function
inverse_floater_price = price_inverse_floater(
    inv_face_value=face_value,
    k_rate=coupon_k,
    maturity=maturity_yrs,
    frequency=pmt_frequency,
    leverage_factor=leverage,
    zcyc=zcyc_data
)




# --- OUTPUT ---
print(f"\nFinal Calculated Price of Inverse Floater: ${inverse_floater_price:.4f}")

Running this script will produce the following output:

--- Inverse Floater Pricing Breakdown ---
Underlying Fixed Coupon (c): 5.5000%
Price of Unit Fixed Bond (Par=100.0): 100.0019
Price of Unit Floater (Par=100.0): 100.0000
Price of Unit Inverse Floater: 100.0038
----------------------------------------

Final Calculated Price of Inverse Floater: $100.0038

This result, $100.0038, perfectly matches the theoretical price we derived in the previous lesson. Our Python implementation successfully translates the replication strategy into executable code, confirming that the price of the inverse floater is indeed .


Conclusion

In this lesson, you have successfully implemented a Python function to price an inverse floating-rate note. By leveraging the principle of replication, you've seen how a seemingly complex valuation can be reduced to a manageable programming task.

Key Takeaways:

  • Modular Implementation: We built our solution on top of reusable functions for pricing standard fixed-rate and floating-rate bonds, which is a robust software design pattern.
  • Code Follows Theory: The price_inverse_floater function is a direct translation of the mathematical formula .
  • From Theory to Practice: You have now completed the journey for this topic, from conceptual understanding and mathematical derivation to a working Python implementation.

With a solid grasp of pricing bonds and their more complex variants, we will now shift our focus from valuation to risk. In the next module, you will learn how to measure a bond's sensitivity to interest rate changes, starting with the foundational concepts of Macaulay and Modified Duration.