yieldcurveml.utils API documentation

# yieldcurveml.utils

View Source

    1from .utils import get_swap_rates, SwapRatesData, swap_cashflows_matrix, SwapCashflows, regression_report
    2
    3__all__ = [
    4    'get_swap_rates',
    5    'SwapRatesData',
    6    'swap_cashflows_matrix',
    7    'SwapCashflows',
    8    'regression_report'
    9]

def get_swap_rates( dataset: Literal['ap10', 'and07', 'ab13e6m', 'ab13ois', 'negativerates']) -> SwapRatesData: View Source

    105def get_swap_rates(dataset: Literal["ap10", "and07", "ab13e6m", "ab13ois", "negativerates"]) -> SwapRatesData:
    106    """
    107    Get example swap rates datasets.
    108
    109    Args:
    110        dataset: String specifying the dataset to use,
    111                one of "ap10", "and07", "ab13e6m", "ab13ois", "negativerates"
    112
    113    Returns:
    114        SwapRatesData containing maturity and rate vectors
    115
    116    Examples:
    117        >>> print(get_swap_rates("ap10"))
    118        SwapRatesData(maturity=array([ 1,  2,  3,  5,  7, 10, 12, 15, 20, 25]),
    119                     rate=array([0.042, 0.043, 0.047, 0.054, 0.057, 0.06 , 0.061, 0.059, 0.056, 0.0555]))
    120    """
    121    # Define all datasets
    122    swap_rates: Dict[str, SwapRatesData] = {
    123        "ap10": SwapRatesData(
    124            maturity=np.array([1, 2, 3, 5, 7, 10, 12, 15, 20, 25]),
    125            rate=np.array([4.2, 4.3, 4.7, 5.4, 5.7, 6, 6.1, 5.9, 5.6, 5.55]) / 100
    126        ),
    127
    128        "and07": SwapRatesData(
    129            maturity=np.array([0.5, 1, 1.5, 2, 2.5, 3, 4, 5, 7, 10, 12, 15, 20, 30]),
    130            rate=np.array([2.75, 3.10, 3.30, 3.43, 3.53, 3.30, 3.78, 3.95,
    131                          4.25, 4.50, 4.65, 4.78, 4.88, 4.85]) / 100
    132        ),
    133
    134        "ab13e6m": SwapRatesData(
    135            maturity=np.array(list(range(1, 31)) + [35, 40, 50, 60]),
    136            rate=np.array([
    137                0.286, 0.324, 0.424, 0.576, 0.762, 0.954, 1.135, 1.303, 1.452, 1.584,
    138                1.703, 1.809, 1.901, 1.976, 2.037, 2.086, 2.123, 2.150, 2.171, 2.187,
    139                2.200, 2.211, 2.220, 2.228, 2.234, 2.239, 2.243, 2.247, 2.251, 2.256,
    140                2.295, 2.348, 2.421, 2.463
    141            ]) / 100
    142        ),
    143
    144        "ab13ois": SwapRatesData(
    145            maturity=np.array(list(range(1, 13)) + [15, 20, 25, 30]),
    146            rate=np.array([
    147                0.000, 0.036, 0.127, 0.274, 0.456, 0.647, 0.827, 0.996, 1.147, 1.280,
    148                1.404, 1.516, 1.764, 1.939, 2.003, 2.038
    149            ]) / 100
    150        ),
    151
    152        "negativerates": SwapRatesData(
    153            maturity=np.array([0.5, 1, 2, 3, 5]),
    154            rate=np.array([-0.00337, -0.003610, -0.003647, -0.003413, -0.003047])
    155        )
    156    }
    157
    158    if dataset not in swap_rates:
    159        raise ValueError(
    160            f"Dataset {dataset} not found. Available datasets: {', '.join(swap_rates.keys())}"
    161        )
    162
    163    return swap_rates[dataset]

Get example swap rates datasets.

Args: dataset: String specifying the dataset to use, one of "ap10", "and07", "ab13e6m", "ab13ois", "negativerates"

Returns: SwapRatesData containing maturity and rate vectors

Examples:

> > > print(get_swap_rates("ap10")) SwapRatesData(maturity=array([ 1, 2, 3, 5, 7, 10, 12, 15, 20, 25]), rate=array([0.042, 0.043, 0.047, 0.054, 0.057, 0.06 , 0.061, 0.059, 0.056, 0.0555]))

class SwapRatesData(typing.NamedTuple): View Source

    17class SwapRatesData(NamedTuple):
    18    maturity: np.ndarray
    19    rate: np.ndarray

SwapRatesData(maturity, rate)

def swap_cashflows_matrix( swap_rates: Union[List[float], numpy.ndarray], maturities: Union[List[float], numpy.ndarray], tenor_swaps: Literal['1m', '3m', '6m', '1y'] = '6m') -> SwapCashflows: View Source

     21def swap_cashflows_matrix(
     22    swap_rates: Union[List[float], np.ndarray],
     23    maturities: Union[List[float], np.ndarray],
     24    tenor_swaps: Literal["1m", "3m", "6m", "1y"] = "6m"
     25) -> SwapCashflows:
     26    """
     27    Creates a matrix of swap cashflows.
     28
     29    Args:
     30        swap_rates: Vector of swap rates
     31        maturities: Vector of maturities (in years)
     32        tenor_swaps: Tenor for the swaps, one of "1m", "3m", "6m", "1y"
     33
     34    Returns:
     35        SwapCashflows object containing:
     36            - nb_swaps: number of swaps
     37            - swaps_maturities: original maturities
     38            - nb_swap_dates: number of cashflow dates per swap
     39            - swap_rates: original swap rates
     40            - cashflow_dates: matrix of cashflow dates
     41            - cashflow_matrix: matrix of cashflows
     42
     43    Example:
     44        >>> rates = [0.02, 0.025, 0.03]
     45        >>> maturities = [1, 2, 3]
     46        >>> result = swap_cashflows_matrix(rates, maturities, "6m")
     47    """
     48    # Convert inputs to numpy arrays if they aren't already
     49    swap_rates = np.array(swap_rates)
     50    maturities = np.array(maturities)
     51
     52    nb_swaps = len(swap_rates)
     53    if nb_swaps != len(maturities):
     54        raise ValueError("There must be as many swap rates as maturities")
     55
     56    # Define frequency mapping
     57    freq_map = {
     58        "1m": 1/12,
     59        "3m": 1/4,
     60        "6m": 1/2,
     61        "1y": 1
     62    }
     63
     64    if tenor_swaps not in freq_map:
     65        raise ValueError("tenor_swaps must be one of: '1m', '3m', '6m', '1y'")
     66
     67    freq = freq_map[tenor_swaps]
     68
     69    # Create cashflow dates
     70    cashflow_dates = np.arange(freq, max(maturities) + freq, freq)
     71    nb_cashflow_dates = len(cashflow_dates)
     72    nb_cashflow_dates_swaps = (1 / freq) * maturities
     73
     74    # Initialize matrices
     75    swap_cashflows_matrix = np.zeros((nb_swaps, nb_cashflow_dates))
     76    cashflow_dates_matrix = np.zeros((nb_swaps, nb_cashflow_dates))
     77    nb_swap_dates = np.zeros(nb_swaps)
     78
     79    # Fill matrices
     80    for i in range(nb_swaps):
     81        nb_cashflow_dates_swaps_i = int(nb_cashflow_dates_swaps[i])
     82        swap_rate_i_times_freq = swap_rates[i] * freq
     83
     84        # Set regular cashflows
     85        swap_cashflows_matrix[i, :nb_cashflow_dates_swaps_i] = swap_rate_i_times_freq
     86        # Add principal repayment at maturity
     87        swap_cashflows_matrix[i, nb_cashflow_dates_swaps_i - 1] += 1
     88
     89        nb_swap_dates[i] = np.sum(swap_cashflows_matrix[i, :] > 0)
     90        cashflow_dates_matrix[i, :nb_cashflow_dates_swaps_i] = cashflow_dates[:nb_cashflow_dates_swaps_i]
     91
     92    # Add row and column names
     93    swap_names = [f"swap{i+1}" for i in range(nb_swaps)]
     94    date_names = [f"{d}y" for d in cashflow_dates]
     95
     96    return SwapCashflows(
     97        nb_swaps=nb_swaps,
     98        swaps_maturities=maturities,
     99        nb_swap_dates=nb_swap_dates,
    100        swap_rates=swap_rates,
    101        cashflow_dates=cashflow_dates_matrix,
    102        cashflow_matrix=swap_cashflows_matrix
    103    )

Creates a matrix of swap cashflows.

Args: swap_rates: Vector of swap rates maturities: Vector of maturities (in years) tenor_swaps: Tenor for the swaps, one of "1m", "3m", "6m", "1y"

Returns: SwapCashflows object containing: - nb_swaps: number of swaps - swaps_maturities: original maturities - nb_swap_dates: number of cashflow dates per swap - swap_rates: original swap rates - cashflow_dates: matrix of cashflow dates - cashflow_matrix: matrix of cashflows

Example:

> > > rates = [0.02, 0.025, 0.03] maturities = [1, 2, 3] result = swap_cashflows_matrix(rates, maturities, "6m")

@dataclass
class SwapCashflows: View Source

     8@dataclass
     9class SwapCashflows:
    10    nb_swaps: int
    11    swaps_maturities: np.ndarray
    12    nb_swap_dates: np.ndarray
    13    swap_rates: np.ndarray
    14    cashflow_dates: np.ndarray
    15    cashflow_matrix: np.ndarray

def regression_report(model: 'CurveStripper', name: str = 'Model') -> str: View Source

    165def regression_report(
    166    model: 'CurveStripper',
    167    name: str = "Model"
    168) -> str:
    169    """Create a formatted report of regression diagnostics for a fitted CurveStripper model.
    170
    171    Parameters
    172    ----------
    173    model : CurveStripper
    174        Fitted CurveStripper model
    175    name : str, default="Model"
    176        Name to use for the model in the report
    177
    178    Returns
    179    -------
    180    str
    181        Formatted report string
    182
    183    Examples
    184    --------
    185    >>> from yieldcurveml.stripcurve import CurveStripper
    186    >>> from sklearn.ensemble import RandomForestRegressor
    187    >>> model = CurveStripper(RandomForestRegressor())
    188    >>> model.fit(X, y)
    189    >>> print(regression_report(model, "RandomForest"))
    190    """
    191    if not hasattr(model, 'curve_rates_'):
    192        raise ValueError("Model must be fitted before generating report")
    193
    194    diagnostics = model.get_diagnostics()
    195
    196    metrics_data = {
    197        'Metric': ['Samples', 'R²', 'RMSE', 'MAE', 'Min Error', 'Max Error'],
    198        name: [
    199            diagnostics.n_samples,
    200            f"{diagnostics.r2_score:.4f}",
    201            f"{diagnostics.rmse:.4f}",
    202            f"{diagnostics.mae:.4f}",
    203            f"{diagnostics.min_error:.4f}",
    204            f"{diagnostics.max_error:.4f}"
    205        ]
    206    }
    207
    208    summary_data = {
    209        'Statistic': ['Mean', 'Std Dev', 'Median', 'MAD', 'Skewness', 'Kurtosis'],
    210        name: [
    211            f"{diagnostics.residuals_summary['mean']:.4f}",
    212            f"{diagnostics.residuals_summary['std']:.4f}",
    213            f"{diagnostics.residuals_summary['median']:.4f}",
    214            f"{diagnostics.residuals_summary['mad']:.4f}",
    215            f"{diagnostics.residuals_summary['skewness']:.4f}",
    216            f"{diagnostics.residuals_summary['kurtosis']:.4f}"
    217        ]
    218    }
    219
    220    percentiles_data = {
    221        'Percentile': ['1%', '5%', '25%', '75%', '95%', '99%'],
    222        name: [
    223            f"{diagnostics.residuals_summary['percentiles']['1%']:.4f}",
    224            f"{diagnostics.residuals_summary['percentiles']['5%']:.4f}",
    225            f"{diagnostics.residuals_summary['percentiles']['25%']:.4f}",
    226            f"{diagnostics.residuals_summary['percentiles']['75%']:.4f}",
    227            f"{diagnostics.residuals_summary['percentiles']['95%']:.4f}",
    228            f"{diagnostics.residuals_summary['percentiles']['99%']:.4f}"
    229        ]
    230    }
    231
    232    metrics_df = pd.DataFrame(metrics_data)
    233    summary_df = pd.DataFrame(summary_data)
    234    percentiles_df = pd.DataFrame(percentiles_data)
    235
    236    report = (
    237        f"\nModel Performance Metrics:\n"
    238        f"{tabulate(metrics_df, headers='keys', tablefmt='pipe', showindex=False)}\n\n"
    239        f"Residuals Summary Statistics:\n"
    240        f"{tabulate(summary_df, headers='keys', tablefmt='pipe', showindex=False)}\n\n"
    241        f"Residuals Percentiles:\n"
    242        f"{tabulate(percentiles_df, headers='keys', tablefmt='pipe', showindex=False)}"
    243    )
    244
    245    return report

Create a formatted report of regression diagnostics for a fitted CurveStripper model.

## Parameters

model : CurveStripper Fitted CurveStripper model name : str, default="Model" Name to use for the model in the report

## Returns

str Formatted report string

## Examples

    >>> from yieldcurveml.stripcurve import CurveStripper
    >>> from sklearn.ensemble import RandomForestRegressor
    >>> model = CurveStripper(RandomForestRegressor())
    >>> model.fit(X, y)
    >>> print(regression_report(model, "RandomForest"))