{ "cells": [ { "cell_type": "markdown", "id": "11bddb7a", "metadata": {}, "source": [ "
" ] }, { "cell_type": "markdown", "id": "1f83085a", "metadata": {}, "source": [ "This notebook analyzes treasury rates by performing eigenvalue decomposition on their covariance matrix. It retrieves treasury rates, calculates their covariance, and uses eigenvalue decomposition to find principal components. The notebook verifies the orthogonality of eigenvectors and extracts the first four principal components. Then, it generates random shocks to simulate their effects on the rates. This is useful for understanding the impact of various factors on interest rates." ] }, { "cell_type": "code", "execution_count": null, "id": "1ca244f6", "metadata": {}, "outputs": [], "source": [ "from openbb import obb\n", "import numpy as np\n", "import pandas as pd" ] }, { "cell_type": "markdown", "id": "db8b1a50", "metadata": {}, "source": [ "Retrieve treasury rates from the OpenBB API, convert to DataFrame, drop NaNs, and convert to decimal format." ] }, { "cell_type": "code", "execution_count": null, "id": "a622e811", "metadata": {}, "outputs": [], "source": [ "rates = (\n", " obb\n", " .fixedincome\n", " .government\n", " .treasury_rates(\n", " start_date=\"2020-01-01\"\n", " )\n", " .to_df()\n", " .dropna()\n", " .div(100)\n", ")" ] }, { "cell_type": "markdown", "id": "6a02b411", "metadata": {}, "source": [ "Display the rates DataFrame." ] }, { "cell_type": "code", "execution_count": null, "id": "ac1345f8", "metadata": {}, "outputs": [], "source": [ "rates" ] }, { "cell_type": "markdown", "id": "b2c5e6c3", "metadata": {}, "source": [ "Calculate the covariance matrix of the treasury rates." ] }, { "cell_type": "code", "execution_count": null, "id": "9bebd6a3", "metadata": {}, "outputs": [], "source": [ "C = rates.cov()" ] }, { "cell_type": "markdown", "id": "c299a5a1", "metadata": {}, "source": [ "Perform eigenvalue decomposition on the covariance matrix to obtain eigenvalues and eigenvectors." ] }, { "cell_type": "code", "execution_count": null, "id": "1040b6d8", "metadata": {}, "outputs": [], "source": [ "eigenvalues, eigenvectors = np.linalg.eig(C)\n", "lambda_sqrt = np.sqrt(eigenvalues)\n", "eigv_decom = np.diag(lambda_sqrt)" ] }, { "cell_type": "markdown", "id": "86b1df03", "metadata": {}, "source": [ "Verify that the eigenvectors are orthogonal by checking if their dot product is the identity matrix." ] }, { "cell_type": "code", "execution_count": null, "id": "6a754189", "metadata": {}, "outputs": [], "source": [ "np.allclose(\n", " eigenvectors.T @ eigenvectors,\n", " np.eye(eigenvectors.shape[0])\n", ")" ] }, { "cell_type": "markdown", "id": "1ea06127", "metadata": {}, "source": [ "Extract the first four principal components and create a DataFrame with meaningful labels." ] }, { "cell_type": "code", "execution_count": null, "id": "066f5d95", "metadata": {}, "outputs": [], "source": [ "B = eigv_decom @ eigenvectors.T\n", "B = pd.DataFrame(\n", " data=B[:4] * 100,\n", " index=[\"wiggle\", \"flex\", \"twist\", \"shift\"],\n", " columns=rates.columns\n", ")" ] }, { "cell_type": "markdown", "id": "4e80c45e", "metadata": {}, "source": [ "Display the principal components DataFrame." ] }, { "cell_type": "code", "execution_count": null, "id": "5eb70388", "metadata": {}, "outputs": [], "source": [ "B" ] }, { "cell_type": "markdown", "id": "da0728d1", "metadata": {}, "source": [ "Generate random shocks from a normal distribution to simulate changes in the rates." ] }, { "cell_type": "code", "execution_count": null, "id": "7aa00db4", "metadata": {}, "outputs": [], "source": [ "random_shocks = np.random.normal(0, 1, size=(4,))\n", "random_shocks @ B" ] }, { "cell_type": "markdown", "id": "a9fe0b61", "metadata": {}, "source": [ "Define standard deviation and correlation matrices for another set of computations." ] }, { "cell_type": "code", "execution_count": null, "id": "9213c16a", "metadata": {}, "outputs": [], "source": [ "S = np.array([0.051, 0.052, 0.061, 0.054])\n", "R = np.array([[1, 0.61, 0.42, 0.31],\n", " [0.61, 1, 0.83, 0.67],\n", " [0.42, 0.83, 1, 0.88],\n", " [0.31, 0.67, 0.88, 1]])" ] }, { "cell_type": "markdown", "id": "3cd0ede5", "metadata": {}, "source": [ "Calculate the covariance matrix using the standard deviation and correlation matrices." ] }, { "cell_type": "code", "execution_count": null, "id": "44be0dc5", "metadata": {}, "outputs": [], "source": [ "C = np.diag(S) @ R @ np.diag(S)" ] }, { "cell_type": "markdown", "id": "b1883d4d", "metadata": {}, "source": [ "Display the calculated covariance matrix." ] }, { "cell_type": "code", "execution_count": null, "id": "1df01307", "metadata": {}, "outputs": [], "source": [ "C" ] }, { "cell_type": "markdown", "id": "38875832", "metadata": {}, "source": [ "Perform eigenvalue decomposition on the new covariance matrix to obtain eigenvalues and eigenvectors." ] }, { "cell_type": "code", "execution_count": null, "id": "ea71473f", "metadata": {}, "outputs": [], "source": [ "eigenvalues, eigenvectors = np.linalg.eig(C)\n", "lambda_sqrt = np.sqrt(eigenvalues)\n", "eigv_decom = np.diag(lambda_sqrt)" ] }, { "cell_type": "markdown", "id": "5b9416f2", "metadata": {}, "source": [ "Display the eigenvectors obtained from the decomposition." ] }, { "cell_type": "code", "execution_count": null, "id": "e1669a19", "metadata": {}, "outputs": [], "source": [ "eigenvectors" ] }, { "cell_type": "markdown", "id": "9116f4e2", "metadata": {}, "source": [ "Verify that the new eigenvectors are orthogonal by checking if their dot product is the identity matrix." ] }, { "cell_type": "code", "execution_count": null, "id": "7cfc7d8a", "metadata": {}, "outputs": [], "source": [ "np.allclose(eigenvectors.T @ eigenvectors, np.eye(eigenvectors.shape[0]))" ] }, { "cell_type": "markdown", "id": "db63d5c8", "metadata": {}, "source": [ "Extract the principal components for the new covariance matrix." ] }, { "cell_type": "code", "execution_count": null, "id": "16ee2ad7", "metadata": {}, "outputs": [], "source": [ "B = eigv_decom @ eigenvectors.T" ] }, { "cell_type": "markdown", "id": "ed135142", "metadata": {}, "source": [ "Display the new principal components." ] }, { "cell_type": "code", "execution_count": null, "id": "b42ac440", "metadata": {}, "outputs": [], "source": [ "B" ] }, { "cell_type": "markdown", "id": "0afd516c", "metadata": {}, "source": [ "Simulate changes in rates using random shocks and basis point adjustments." ] }, { "cell_type": "code", "execution_count": null, "id": "845e8d19", "metadata": {}, "outputs": [], "source": [ "m = 2\n", "random_shocks = np.random.normal(0, 1, size=(4,))\n", "random_shocks[2:] *= m # Apply magnitude to z3 and z4\n", "delta_r = random_shocks @ (100 * B) # Basis point shocks for each rate point" ] }, { "cell_type": "markdown", "id": "0dc9bd1c", "metadata": {}, "source": [ "Display the simulated rate changes." ] }, { "cell_type": "code", "execution_count": null, "id": "aede691d", "metadata": {}, "outputs": [], "source": [ "delta_r" ] }, { "cell_type": "markdown", "id": "47b0dc11", "metadata": {}, "source": [ "PyQuant News is where finance practitioners level up with Python for quant finance, algorithmic trading, and market data analysis. Looking to get started? Check out the fastest growing, top-selling course to get started with Python for quant finance. For educational purposes. Not investment advise. Use at your own risk." ] } ], "metadata": { "jupytext": { "cell_metadata_filter": "-all", "main_language": "python", "notebook_metadata_filter": "-all" } }, "nbformat": 4, "nbformat_minor": 5 }