{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "colab": { "name": "0280_bonos.ipynb", "provenance": [], "authorship_tag": "ABX9TyPEBDNmz+jV9eQET/0t2ATM", "include_colab_link": true }, "kernelspec": { "name": "python3", "display_name": "Python 3" }, "language_info": { "name": "python" } }, "cells": [ { "cell_type": "markdown", "metadata": { "id": "view-in-github", "colab_type": "text" }, "source": [ "\"Open" ] }, { "cell_type": "markdown", "source": [ "# Bonos, ETTI, forward, arbitraje\n", "## Calcular el precio de un bono\n", "Puede consultar el archivo de Excel: [excel_para_pyhton.xlsm](https://www.dropbox.com/s/wzq2y2k97c1d6rg/excel_para_pyhton.xlsm?dl=1)" ], "metadata": { "id": "B4bN27eR0sZc" } }, { "cell_type": "markdown", "source": [ "## Precio utilizando la TIR\n", "Puede ver la **Hoja1** del documento de Excel.\n", "\n", "\n", "Supongamos un bono con las siguientes características:\n", "* Nominal 1.000 €\n", "* Cupón anual 10%\n", "* Madura al quinto año\n", "* TIR: r = 8%\n", "\n", "Se pide:\n", "* Calcular el precio del bono\n", "* Una vez conocido el precio del bono, comprobar que la TIR coincide con el dato proporcionado\n", "\n" ], "metadata": { "id": "JmYBhyuovEeU" } }, { "cell_type": "code", "source": [ "pip install numpy-financial" ], "metadata": { "id": "9Bxe_9100HAc", "outputId": "8728a8aa-f17b-413b-de2a-e8f1c01b0d22", "colab": { "base_uri": "https://localhost:8080/" } }, "execution_count": 1, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Requirement already satisfied: numpy-financial in /usr/local/lib/python3.10/dist-packages (1.0.0)\n", "Requirement already satisfied: numpy>=1.15 in /usr/local/lib/python3.10/dist-packages (from numpy-financial) (1.23.5)\n" ] } ] }, { "cell_type": "code", "source": [ "import numpy_financial as npf\n", "\n", "# DATOS DEL BONO\n", "nominal = 1000\n", "cupon = 0.1\n", "n = 5 # años\n", "r = 0.08\n", "\n", "# FLUJOS DE CAJA\n", "flujos = [0]\n", "for i in range(1, n+1):\n", " if i < n:\n", " flujos.append(cupon * nominal)\n", " elif i == n:\n", " flujos.append(cupon * nominal + nominal)\n", "print(\"Flujos de caja: \", flujos)\n", "\n", "# PRECIO DEL BONO\n", "precio = 0\n", "for i in range(1, n+1):\n", " precio += flujos[i] / (1+r)**i\n", "print(\"Precio del bono:\", precio)\n", "bono = flujos[:]\n", "bono[0] = -precio\n", "\n", "# COMPROBACIÓN TIR = r\n", "tir = npf.irr(bono)\n", "print(f\"La TIR del bono es: {tir:.5%}\") # Internal rate of return" ], "metadata": { "id": "BICvhexvwKSV", "outputId": "6e59ffb9-078c-49c1-9ccc-60cd27a41ea6", "colab": { "base_uri": "https://localhost:8080/" } }, "execution_count": 2, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Flujos de caja: [0, 100.0, 100.0, 100.0, 100.0, 1100.0]\n", "Precio del bono: 1079.8542007415613\n", "La TIR del bono es: 8.00000%\n" ] } ] }, { "cell_type": "markdown", "source": [ "## Precio utilizando la ETTI\n", "Puede ver la **Hoja2** del documento de Excel.\n", "\n", "\n", "Supongamos un bono con las siguientes características:\n", "* Nominal 1.000 €\n", "* Cupón anual 10%\n", "* Madura al quinto año\n", "* La ETTI para los diferentes años es:\n", " - año 1: 2%\n", " - año 2: 4%\n", " - año 3: 6%\n", " - año 4: 8%\n", " - año 5: 10%\n", "\n", "Se pide:\n", "* Calcular el precio del bono\n", "* Calcular la TIR" ], "metadata": { "id": "M-sr_4rn03-f" } }, { "cell_type": "code", "source": [ "import numpy_financial as npf\n", "\n", "# DATOS\n", "nominal = 1000\n", "cupon = 0.1\n", "n = 5 # años\n", "r01 = 0.02\n", "r02 = 0.04\n", "r03 = 0.06\n", "r04 = 0.08\n", "r05 = 0.10\n", "etti = [r01,r02,r03,r04,r05]\n", "\n", "# FLUJOS DE CAJA\n", "flujos = [0]\n", "for i in range(1, n+1):\n", " if i < n:\n", " flujos.append(cupon * nominal)\n", " elif i == n:\n", " flujos.append(cupon * nominal + nominal)\n", "print(\"Flujos de caja: \", flujos)\n", "\n", "# PRECIO DEL BONO CON LA ETTI\n", "precio = 0\n", "for i in range(1, n+1):\n", " precio += flujos[i] / (1+etti[i-1])**i\n", "print(\"Precio del bono:\", precio)\n", "bono = flujos[:]\n", "bono[0] = -precio\n", "\n", "# CALCULAR LA TIR DEL BONO TIR = r\n", "tir = npf.irr(bono)\n", "print(f\"La TIR del bono es: {tir:.6%}\") # Internal rate of return" ], "metadata": { "id": "C4avZNvy1cVw", "outputId": "41442eaa-0fca-4773-ad66-ae96ed39be35", "colab": { "base_uri": "https://localhost:8080/" } }, "execution_count": 3, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Flujos de caja: [0, 100.0, 100.0, 100.0, 100.0, 1100.0]\n", "Precio del bono: 1030.9732059359958\n", "La TIR del bono es: 9.199575%\n" ] } ] }, { "cell_type": "markdown", "source": [ "## Creación de un bono sintético cupón cero\n", "Puede ver la **Hoja3** del documento de Excel.\n", "\n", "\n", "Supongamos dos bonos A y B, ambos a 5 años con las siguientes características:\n", "* Bono A\n", " - Nominal: 10.000 €\n", " - Cupón anual: 2%\n", "* Bono B\n", " - Nominal: 4.000 €\n", " - Cupón anual: 25%\n", "* La ETTI para los diferentes años es:\n", " - año 1: 2%\n", " - año 2: 4%\n", " - año 3: 6%\n", " - año 4: 8%\n", " - año 5: 10%\n", "\n", "Se pide:\n", "* Calcular el precio de ambos bonos\n", "* Calcular la TIR de ambos bonos\n", "* Crear el bono C que es un bono sintético que se forma combinando los bonos A y B para conseguir un bono cupón cero a 5 años.\n", "* Calcular la TIR del bono C y comprobar que es igual a la ETTI a 5 años, que es del 10%." ], "metadata": { "id": "E_9tdEMnmZTT" } }, { "cell_type": "code", "source": [ "import numpy_financial as npf\n", "\n", "# DATOS BONO A\n", "nominalA = 10_000\n", "cuponA = 0.02\n", "n = 5 # años, para A y B\n", "# DATOS BONO B\n", "nominalB = 4_000\n", "cuponB = 0.25\n", "# ETTI\n", "etti =[.02,.04,.06,.08,.10]\n", "\n", "# FLUJOS DE CAJA DE LOS BONOS\n", "def flujos(nominal, cupon, n):\n", " cf = [0] # array con el cash flow\n", " for i in range(1, n+1):\n", " if i < n:\n", " cf.append(cupon * nominal)\n", " elif i == n:\n", " cf.append(cupon * nominal + nominal)\n", " return cf\n", "\n", "# Flujos de caja de los Bonos A y B\n", "flujosA = flujos(nominalA, cuponA, n)\n", "flujosB = flujos(nominalB, cuponB, n)\n", "\n", "# PRECIO DE UN BONO CON LA ETTI\n", "def precio_etti(flujos, etti):\n", " precio = 0\n", " for i in range(1, n+1):\n", " precio += flujos[i] * (1+etti[i-1])**-i\n", " return precio\n", "\n", "# Precios de los Bonos A y B\n", "precioA = precio_etti(flujosA, etti)\n", "precioB = precio_etti(flujosB, etti)\n", "print(f\"El precio del bono A es {precioA}\")\n", "print(f\"El precio del bono B es {precioB}\")\n", "# Flujos de caja de los bonos A y B\n", "bonoA = flujosA[:]\n", "bonoA[0] = -precioA\n", "bonoB = flujosB[:]\n", "bonoB[0] = -precioB\n", "\n", "# CREACIÓN DEL BONO SINTÉTICO C\n", "\n", "# m es el número de bonos que se han de comprar o vender de uno de los bonos\n", "m = max(cuponA*nominalA, cuponB*nominalB) / min(cuponB*nominalB, cuponA*nominalA)\n", "# con los datos de ejemplo m = 1000 / 200 = 5\n", "\n", "# Flujos de caja del bono C\n", "bonoC = [0]*(n+1)\n", "for i in range(0, n+1):\n", " bonoC[i] = m * bonoA[i] - bonoB[i]\n", "print(f\"Flujos de caja del bono C: {bonoC}\")\n", "\n", "# Calcular la TIR de los bonos\n", "tirA = npf.irr(bonoA)\n", "tirB = npf.irr(bonoB)\n", "tirC = npf.irr(bonoC)\n", "print(f\"La TIR del bono A es: {tirA:.6%}\")\n", "print(f\"La TIR del bono B es: {tirB:.6%}\")\n", "print(f\"La TIR del bono C es: {tirC:.6%}\")" ], "metadata": { "id": "ZVQQqkConm5R", "outputId": "986bf69b-df6a-47d3-dd43-6b66836f2402", "colab": { "base_uri": "https://localhost:8080/" } }, "execution_count": 4, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "El precio del bono A es 7029.316996345231\n", "El precio del bono B es 6584.2041210050265\n", "Flujos de caja del bono C: [-28562.38086072113, 0.0, 0.0, 0.0, 0.0, 46000.0]\n", "La TIR del bono A es: 9.795736%\n", "La TIR del bono B es: 8.573790%\n", "La TIR del bono C es: 10.000000%\n" ] } ] }, { "cell_type": "markdown", "source": [ "## Reinversión de flujos de caja intermedios\n", "Puede ver la **Hoja4** del documento de Excel.\n", "\n", "\n", "La importancia de trabajar con bonos cupón cero.\n", "\n", "La TIR es la Tasa Interna de Rentabilidad, la palabra 'Interna' indica que si la operación financiera analizada se mezcla con otras operaciones la rentabilidad prometida por la TIR se podría alterar.\n", "\n", "Una operación de inversión que tenga flujos de caja intermedios, por ejemplo un bono cupón explícito, puede no proporcionar a su propietario la rentabilidad que promete la TIR del bono si el inversor no se preocupa de reinvertir los flujos de caja intermedios hasta el final de la operación.\n", "\n", "Supongamos un bono cupón explícito con las siguientes características:\n", "* Nominal 10.000 €\n", "* Cupón 10%\n", "* Madura a los 10 años\n", "* Precio de adquisición 10.000 €\n", "\n", "Se pide:\n", "* Calcular la TIR del bono\n", "* Calcular la rentabilidad del inversor supueto que reinvierta los flujos de caja intermedios hasta el momento de vencimiento, a las siguientes rentabilidades:\n", " - al 0%\n", " - al 10%\n", " - al 20%\n", "* Crear un bono cupón cero, al mismo plazo, por el mismo precio, cuyo último flujo de caja sea el necesario para proporcionar una rentabilidad del 10% y comprobar que su TIR es de 10%." ], "metadata": { "id": "8SVSQyGs1H0P" } }, { "cell_type": "code", "source": [ "import numpy_financial as npf\n", "\n", "# DATOS\n", "nominal = 10_000\n", "cupon = .1\n", "n = 10 # años\n", "precio = 10_000\n", "\n", "# Flujos de caja del bono\n", "cf = [0]*(n+1)\n", "for i in range(1,n+1):\n", " cf[i] = cupon * nominal\n", "cf[n] += nominal\n", "cf[0] = -precio\n", "\n", "print(f\"La TIR del bono es: {npf.irr(cf):.2%}\")\n", "\n", "# Montante de la Reinversión\n", "def montante(cf,r):\n", " m = 0 # montante\n", " for i in range(1, n+1):\n", " m += cf[i]*(1+r)**(n-i)\n", " return m\n", "\n", "tasas_reinversion = [0,.1,.2]\n", "for t in tasas_reinversion:\n", " m = montante(cf,t)\n", " print()\n", " print(f\"El montante reinvirtiendo al tanto del {t:.0%} es {m:,.2f} €\")\n", " print(f\"La rentabilidad del inversor reinvirtiendo al tanto {t:.0%} es {(m/precio)**(1/n)-1:.2%}\")" ], "metadata": { "id": "n6mxKhMZ69qn", "outputId": "dadab3ed-5cc7-4c78-db64-4261a44ee742", "colab": { "base_uri": "https://localhost:8080/" } }, "execution_count": 5, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "La TIR del bono es: 10.00%\n", "\n", "El montante reinvirtiendo al tanto del 0% es 20,000.00 €\n", "La rentabilidad del inversor reinvirtiendo al tanto 0% es 7.18%\n", "\n", "El montante reinvirtiendo al tanto del 10% es 25,937.42 €\n", "La rentabilidad del inversor reinvirtiendo al tanto 10% es 10.00%\n", "\n", "El montante reinvirtiendo al tanto del 20% es 35,958.68 €\n", "La rentabilidad del inversor reinvirtiendo al tanto 20% es 13.65%\n" ] } ] }, { "cell_type": "markdown", "source": [ "## Comparación entre una inversión cierta y otra aleatoria\n", "Puede ver la **Hoja5** del documento de Excel.\n", "\n", "\n", "Comparemos dos inversiones A y B, ambas de duración 1 año y que proporcionan ambas un 10% anual, con una inversión de un millón de euros cada una. La inversión A es cierta, esto supone que existe un 100% de probabilidad de que el flujo de caja final sea 1.100.000 €. La inversión B, tiene una probabilidad del 1% de que el montante final sea m1, y una probabilidad del 99% de que el montante final sea m2. \n", "Se pide: \n", "* Caso 1: si m1 = 0, calcular m2, para que la rentabilidad esperada de la inversión B sea del 10%\n", "* Caso 2: si m1 = 500.000, calcular m2, para que la rentabildidad esperada de B sea el 10%\n", "* Comprobar que la TIR de ambas inversiones es del 10%" ], "metadata": { "id": "PimtEH6Pdmkf" } }, { "cell_type": "code", "source": [ "import numpy_financial as npf\n", "\n", "# DATOS\n", "c = 1_000_000 # capital inicial\n", "r = .1 # rentabilidad 10% anual\n", "ma = c*(1+r) # Montante A: el montante de la inversión A es 1.100.000\n", "p = .01 # probabilidad de que suceda una de las ramas de la inverión B\n", "q = 1-p # probabilidad complementaria de la otra rama de B, se cumple que p+q=1\n", "\n", "# Cálculo de mb2\n", "# El montante de la inversión B es mb y tiene dos componentes mb1 + mb2 = mb\n", "def mb_2(ma,p,mb1):\n", " return (ma - p * mb1) / q\n", "\n", "# Resultados\n", "print(\"CASO 1\")\n", "mb1 = 500_000 # primer caso que nos piden\n", "mb2 = mb_2(ma,p,mb1)\n", "print(f\"Si el montante alcanzado con mb1 es {mb1:,} entonces el montante mb2 es {mb2:,.2f}\")\n", "print(f\"La TIR de la inversión B1 es: {npf.irr([-c,mb1]):.1%}\")\n", "print(f\"La TIR de la inversión B2 es: {npf.irr([-c,mb2]):.2%}\")\n", "print(f\"La TIR de la inversión A es: {npf.irr([-c, ma]):.1%}\") # comprobar que ambas TIR son del 10%\n", "print(f\"La TIR de la inversión B es: {npf.irr([-c, p*mb1+q*mb2]):.1%}\") # comprobar que ambas TIR son del 10%\n", "print()\n", "\n", "print(\"CASO 2\")\n", "mb1 = 0 # segundo caso que nos piden\n", "mb2 = mb_2(ma,p,mb1)\n", "print(f\"Si el montante alcanzado con mb1 es {mb1} entonces el montante mb2 es {mb2:,.2f}\")\n", "print(f\"La TIR de la inversión B1 es: {npf.irr([-c,mb1]):.1%}\")\n", "print(f\"La TIR de la inversión B2 es: {npf.irr([-c,mb2]):.2%}\")\n", "print(f\"La TIR de la inversión A es: {npf.irr([-c, ma]):.1%}\") # comprobar que ambas TIR son del 10%\n", "print(f\"La TIR de la inversión B es: {npf.irr([-c, p*mb1+q*mb2]):.1%}\") # comprobar que ambas TIR son del 10%" ], "metadata": { "id": "YnP26gg_F5jR", "outputId": "2e5deada-39d8-454c-fdc7-9505fb6709e7", "colab": { "base_uri": "https://localhost:8080/" } }, "execution_count": 6, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "CASO 1\n", "Si el montante alcanzado con mb1 es 500,000 entonces el montante mb2 es 1,106,060.61\n", "La TIR de la inversión B1 es: -50.0%\n", "La TIR de la inversión B2 es: 10.61%\n", "La TIR de la inversión A es: 10.0%\n", "La TIR de la inversión B es: 10.0%\n", "\n", "CASO 2\n", "Si el montante alcanzado con mb1 es 0 entonces el montante mb2 es 1,111,111.11\n", "La TIR de la inversión B1 es: nan%\n", "La TIR de la inversión B2 es: 11.11%\n", "La TIR de la inversión A es: 10.0%\n", "La TIR de la inversión B es: 10.0%\n" ] } ] }, { "cell_type": "markdown", "source": [ "## Forward $r_{12}$ conocidos dos bonos\n", "Puede ver la **Hoja6** del documento de Excel.\n", "\n", "\n", "En el mercado cotizan los bonos A y B.\n", "* El bono A es un bono cupón cero de duración un año y TIR del 10%\n", "* El bono B es un bono cupón explícito de 4.400 € anuales, nominal 10.000 €, duración 2 años y precio de 14.000 €\n", "* El bono C es un bono cupón cero a dos años, que se obtiene como bono sintético combinando los bonos A y B\n", "\n", "Se pide:\n", "* Calcular la TIR del bono C\n", "* Comprobar que la TIR del bono C es el punto de la ETTI a dos años ($r_{02}$). Para hacer la comprobación calcular con la ETTI los precios de los bonos A, B y C y comprobar que coinciden con los previstos.\n", "* Comprobar que el nominal elegido para el bono A puede ser cualquiera, es arbitrario." ], "metadata": { "id": "RciGu9_wF5Sg" } }, { "cell_type": "code", "source": [ "import numpy_financial as npf\n", "from random import randint, seed\n", "seed()\n", "\n", "# DATOS\n", "tirA = .1\n", "cuponB = 4_400\n", "nominalB = 10_000\n", "precioB = 14_000\n", "nominalA = randint(1,10000)\n", "print(f\"El nominal elegido para el bono A es {nominalA}\")\n", "\n", "# FLUJOS DE CAJA bonos A y B\n", "bonoB = [-precioB, cuponB, cuponB+nominalB]\n", "bonoA = [-nominalA/(1+tirA), nominalA, 0] # añadimos un flujo 0 en t=2 por comodidad, para luego restar flujos\n", "m = bonoB[1]/bonoA[1]\n", "print(f\"El multiplicador m es {m}\")\n", "bonoC = [bonoB[0]-m*bonoA[0], bonoB[1]-m*bonoA[1], bonoB[2]-m*bonoA[2]]\n", "print(\"Bono C: \", bonoC)\n", "\n", "# TIR del bono C\n", "tirC = npf.irr(bonoC)\n", "print(f\"La TIR del bono C es: {tirC:.6%}\")\n", "\n", "# Creación de la ETTI\n", "etti = [tirA, tirC] # la tirC si pertenece a la ETTI por ser un bono cupón cero, pero la tirB no pertenece\n", "\n", "# COMPROBAR PRECIOS CON LA ETTI\n", "def precio_etti(flujos, etti):\n", " precio = 0\n", " for i in range(1, len(flujos)):\n", " precio += flujos[i] * (1+etti[i-1])**-i\n", " return precio\n", "\n", "# Precios de los Bonos A, B y C\n", "precioA = precio_etti(bonoA, etti)\n", "precioB = precio_etti(bonoB, etti)\n", "precioC = precio_etti(bonoC, etti)\n", "print(f\"La diferencia de precios en el bono A es {precioA+bonoA[0]}\")\n", "print(f\"La diferencia de precios en el bono B es {precioB+bonoB[0]}\")\n", "print(f\"La diferencia de precios en el bono C es {precioC+bonoC[0]}\")" ], "metadata": { "id": "_iuezG3YGIkK", "outputId": "7c84a82d-817f-449d-ad11-a214e0df053d", "colab": { "base_uri": "https://localhost:8080/" } }, "execution_count": 7, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "El nominal elegido para el bono A es 517\n", "El multiplicador m es 8.51063829787234\n", "Bono C: [-10000.0, 0.0, 14400.0]\n", "La TIR del bono C es: 20.000000%\n", "La diferencia de precios en el bono A es 5.684341886080802e-14\n", "La diferencia de precios en el bono B es -3.637978807091713e-12\n", "La diferencia de precios en el bono C es -3.637978807091713e-12\n" ] } ] }, { "cell_type": "markdown", "source": [ "## Calcular la ETTI con una cartera de tres bonos\n", "Puede ver la **Hoja7** del documento de Excel.\n", "\n", "### FASE 1\n", "En el mercado cotizan los bonos A , B y C.\n", "* El bono A es un bono cupón cero a un año de nominal 1.000 € y TIR del 10%\n", "* El bono B es un bono cupón explícito de 90 € anuales, nominal 1.000 € y duración 2 años\n", "* El bono C es un bono cupón explícito de 500 € anuales, nominal 1.000 € y duración 3 años\n", "* Conocemos la ETTI a 1, 2 y 3 años que es 10%, 20% y 30%, respectivamente \n", "\n", "Se pide:\n", "* Calcular los precios de los bonos A, B y C\n", "* Calcular la TIR de los bonos A, B y C\n", "\n", "### FASE 2\n", "Supongamos conocidos los flujos de caja de los bonos A, B y C incluidos sus precios. \n", "\n", "Se pide:\n", "* Calcular la ETTI de los años 1, 2 y 3." ], "metadata": { "id": "pVV6cf_9_rSq" } }, { "cell_type": "code", "source": [ "import numpy_financial as npf\n", "\n", "##### FASE 1 #####\n", "# Flujos de caja de los bonos\n", "bonoA = [0,1000,0,0] # inicialmente el flujo de caja inicial es cero\n", "bonoB = [0,90,1090,0]\n", "bonoC = [0,500,500,1500]\n", "\n", "# Calcular el precio de los bonos dada la ETTI\n", "etti = [.1, .2, .3]\n", "def precio_etti(flujos, etti):\n", " precio = 0\n", " for i in range(1, len(flujos)):\n", " precio += flujos[i] * (1+etti[i-1])**-i\n", " return precio\n", "\n", "precioA = precio_etti(bonoA, etti)\n", "precioB = precio_etti(bonoB, etti)\n", "precioC = precio_etti(bonoC, etti)\n", "print(f\"El precio del bono A es {precioA:,.2f} €\")\n", "print(f\"El precio del bono B es {precioB:,.2f} €\")\n", "print(f\"El precio del bono C es {precioC:,.2f} €\")\n", "print()\n", "\n", "# Calcular la TIR de los bonos\n", "bonoA[0] = -precioA\n", "bonoB[0] = -precioB\n", "bonoC[0] = -precioC\n", "\n", "tirA = npf.irr(bonoA)\n", "tirB = npf.irr(bonoB)\n", "tirC = npf.irr(bonoC)\n", "\n", "print(f\"La TIR del bono A es: {tirA:.2%}\")\n", "print(f\"La TIR del bono B es: {tirB:.2%}\")\n", "print(f\"La TIR del bono C es: {tirC:.2%}\")\n", "print()\n", "\n", "##### FASE 2 #####\n", "etti_calculada = [0,0,0] # inicializamos el array\n", "etti_calculada[0] = tirA # la ETTI del año 1 es la TIR del bono A por ser un bono cupón cero a un año\n", "def calcula_etti(bono, etti_calculada):\n", " n = [i for i, e in enumerate(bono) if e != 0][-1]\n", " ultimo_flujo = bono[n]\n", " precio = -bono[0]\n", " fcid = 0 # inicializamos los flujos de caja intermedios descontados\n", " for t in range(1,n): # recorre los flujos de caja intermedios\n", " fcid += bono[t] / (1+etti[t-1])**t\n", " return (ultimo_flujo / (precio - fcid))**(1/n)-1\n", "\n", "r02 = calcula_etti(bonoB, etti_calculada) # calculamos r02 conocido el bono B y r01\n", "etti_calculada[1] = r02\n", "\n", "r03 = calcula_etti(bonoC, etti_calculada) # calculamos r03 conocido el bono C, r01 y r02\n", "etti_calculada[2] = r03\n", "\n", "# Imprime la etti_calculada\n", "for i in range(len(etti_calculada)):\n", " print(f\"La ETTI del año {i+1} es {etti_calculada[i]:.2%}\")" ], "metadata": { "id": "4IFo_UqkAKU-", "outputId": "c2009eb3-30da-4555-82b7-08265570f8dc", "colab": { "base_uri": "https://localhost:8080/" } }, "execution_count": 8, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "El precio del bono A es 909.09 €\n", "El precio del bono B es 838.76 €\n", "El precio del bono C es 1,484.52 €\n", "\n", "La TIR del bono A es: 10.00%\n", "La TIR del bono B es: 19.49%\n", "La TIR del bono C es: 25.13%\n", "\n", "La ETTI del año 1 es 10.00%\n", "La ETTI del año 2 es 20.00%\n", "La ETTI del año 3 es 30.00%\n" ] } ] }, { "cell_type": "code", "source": [ "# Para calcular n\n", "bonoA = [0,1000,0,0] # n = 1, vector = [1]\n", "bonoB = [0,90,1090,0] # n = 2, vector = [1, 2]\n", "bonoC = [0,500,500,1500] # n = 3, vector = [1, 2, 3]\n", "bono = bonoA\n", "vector = [i for i, e in enumerate(bono) if e != 0] # list comprhension\n", "print(vector[-1])" ], "metadata": { "id": "ELfb3GBvg6bF", "outputId": "8334bb9f-5d24-46fe-8007-413a7cc3d7eb", "colab": { "base_uri": "https://localhost:8080/" } }, "execution_count": 9, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "1\n" ] } ] }, { "cell_type": "markdown", "source": [ "## Arbitraje\n", "Puede consultar el archivo de Excel: [arbitraje_con_bonos.xlsx](https://www.dropbox.com/s/vom9tvkf0upfl4b/arbitraje_con_bonos.xlsx?dl=1)\n", "\n", "\n", "### Ejemplo sencillo\n", "Puede ver la **Hoja1** del documento de Excel.\n", "\n", "Supongamos dos fruterías donde venden el mismo tipo de manzana.\n", "* Tienda A: precio 100 céntimos/Kg\n", "* Tienda B: precio 160 céntimos/Kg\n", "\n", "Operamos bajo el supuesto de que en cada tienda podemos comprar o vender las manzanas.\n", "\n", "Estrategia de arbitraje:\n", "* Compramos las manzanas en la tiena A, donde el precio es más barato\n", "* Vendemos las manzanas en la tienda B, donde el precio es más caro\n", "\n", "La estrategia consiste en comprar el activo infravalorado y vender el activo sobrevalorado.\n", "\n", "De esta forma estaríamos ganando la diferencia.\n", "\n", "### Introduciendo intereses\n", "Supongamos que el caso anterior de compraventa no se produce simultáneamente en el tiempo y que necesitamos financiar nuestra compra durante un tiempo.\n", "* Duración de la operación: 1 año\n", "* Tipo de interés: 10% anual\n", "* En t=0 pedimos un prestamo de 100 para comprar en la tienda A\n", "* En t=0 compramos las manzanas en la tienda A por 100\n", "* En t=1 vendemos las manzanas en la tienda B por 160\n", "* En t=1 devolvemos el préstamo 100*(1+0.1) = 110\n", "* Beneficio obtenido:\n", " - Método 1: 160-100-10 = 50 en t=1\n", " - Método 2: 100-100+160-110 = 50 en t=1\n" ], "metadata": { "id": "a0oZL-JNj_L0" } }, { "cell_type": "code", "execution_count": 10, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "XeU3JN-pj-Hb", "outputId": "b312ef50-cf31-4224-fd5d-3cf5fa1862ca" }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Los flujos de caja de la operación en los diferentes años son: [0, 50.0]\n" ] } ], "source": [ "precioA = 100\n", "precioB = 160\n", "n = 1 # duración en años\n", "Co = precioA # Capital inicial prestado\n", "r = .1 # tipo de interés anual\n", "Cn = Co*(1+r)**n\n", "flujos_caja = [Co-precioA, round(precioB-Cn,8)]\n", "print(f\"Los flujos de caja de la operación en los diferentes años son: {flujos_caja}\")" ] }, { "cell_type": "markdown", "source": [ "### Arbitraje en el mercado de bonos\n", "Puede ver la **Hoja2** del documento de Excel.\n", "\n", "Disponemos de dos bonos que maduran a dos años, ambos de cupón explícito y con diferente duración de Macaulay (*duration*).\n", "* El bono A tiene un cupón anual de 10 € y nominal de 1.000 €.\n", "* El bono B tiene un cupón anual de 200 € y nominal de 1.000 €.\n", "* Conocemos la ETTI a un año (5%) y a dos años (20%).\n", "* Supongamos que en el mercado los inversores compran el bono A que es el de mayor TIR y desprecian el bono B. La presión de las compras hace que el precio del bono A suba, haciendo que su TIR baje hasta llegar a coincidir con la del bono B.\n", "\n", "Se pide: \n", "* Calcular el precio de los bonos A y B\n", "* Calcular la TIR de los bonos A y B\n", "* Calcular la *duratin* de ambos bonos\n", "* Ante este mercado desequilibrado:\n", " - calcular el nuevo precio que tendrá el bono A\n", " - establecer la estrategia de arbitraje que permitiría obtener ventaja\n", " - determinar el beneficio obtenido por el arbitraje y en que instante se produciría.\n" ], "metadata": { "id": "BGvXV4TVL1cc" } }, { "cell_type": "code", "source": [ "pip install numpy-financial" ], "metadata": { "id": "8TVRhBqST-Ln", "outputId": "bab9a90b-ab69-404d-f435-57fa740877ec", "colab": { "base_uri": "https://localhost:8080/" } }, "execution_count": 11, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Requirement already satisfied: numpy-financial in /usr/local/lib/python3.10/dist-packages (1.0.0)\n", "Requirement already satisfied: numpy>=1.15 in /usr/local/lib/python3.10/dist-packages (from numpy-financial) (1.23.5)\n" ] } ] }, { "cell_type": "code", "source": [ "import numpy_financial as npf\n", "import numpy as np # la librería numpy nos permitirá trabajar con ndarrays\n", "\n", "# DATOS\n", "bonoA = [0, 10, 1010]\n", "bonoB = [0, 200, 1200]\n", "etti = [.05, .2]\n", "\n", "# PRECIO DE UN BONO CON LA ETTI\n", "def precio_etti(flujos, etti):\n", " precio = 0\n", " for i in range(1, len(bonoA)):\n", " precio += flujos[i] * (1+etti[i-1])**-i\n", " return precio\n", "\n", "# Precios de los Bonos A y B\n", "precioA = precio_etti(bonoA, etti)\n", "precioB = precio_etti(bonoB, etti)\n", "print(f\"El precio del bono A es {precioA}\")\n", "print(f\"El precio del bono B es {precioB}\")\n", "# Flujos de caja de los bonos A y B\n", "bonoA[0] = -precioA\n", "bonoB[0] = -precioB\n", "\n", "# Calcular la TIR de los bonos\n", "tirA = npf.irr(bonoA)\n", "tirB = npf.irr(bonoB)\n", "print(f\"La TIR del bono A es: {tirA:.4%}\")\n", "print(f\"La TIR del bono B es: {tirB:.4%}\")\n", "\n", "# Calcular la duración de Macaulay\n", "def duracion(bono):\n", " tir =npf.irr(bono)\n", " precio = 0\n", " numerador = 0\n", " for i in range(1, len(bonoA)):\n", " precio += bono[i] * (1+tir)**-i\n", " numerador += i * bono[i] * (1+tir)**-i\n", " return numerador / precio\n", "\n", "print(f\"La duration del bono A es {duracion(bonoA)}\")\n", "print(f\"La duration del bono B es {duracion(bonoB)}\")\n", "\n", "# Nuevo precio del bono A en el mercado desequilibrado\n", "precioAprima = npf.npv(tirB, bonoA) + precioA # sumamos el antiguo precio de A ya que va en la posición [0] del array con signo negativo\n", "print(f\"El nuevo precio del bono A en el mercado desequilibrado es {precioAprima}\")\n", "bonoAprima =[-precioAprima, bonoA[1], bonoA[2]]\n", "\n", "# Bono C = B - 20A'\n", "# bonoC = bonoB - 20 * bonoAprima # esto da error, necesitamos trabajar con ndarrays\n", "bonoB_arr = np.array(bonoB)\n", "bonoAprima_arr =np.array(bonoAprima)\n", "bonoC_arr = bonoB_arr - 20 * bonoAprima_arr\n", "print(f\"El bono C es {bonoC_arr}\")\n", "\n", "# Ajustamos con un préstamo\n", "prestamo = np.array([bonoC_arr[2] / (1+etti[1])**2, 0, -bonoC_arr[2]])\n", "print(f\"El préstamo es {prestamo}\")\n", "\n", "# Cartera Total\n", "total = bonoC_arr + prestamo\n", "print(f\"Cartera resultante del arbitraje {total}\")" ], "metadata": { "id": "N_5NXsIQTvc5", "outputId": "ae0032ad-03a6-4743-e632-b9d2da800632", "colab": { "base_uri": "https://localhost:8080/" } }, "execution_count": 12, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "El precio del bono A es 710.9126984126985\n", "El precio del bono B es 1023.809523809524\n", "La TIR del bono A es: 19.8989%\n", "La TIR del bono B es: 18.4704%\n", "La duration del bono A es 1.988268094271526\n", "La duration del bono B es 1.8351074725250018\n", "El nuevo precio del bono A en el mercado desequilibrado es 728.0583383461574\n", "El bono C es [ 13537.35724311 0. -19000. ]\n", "El préstamo es [-13194.44444444 0. 19000. ]\n", "Cartera resultante del arbitraje [342.91279867 0. 0. ]\n" ] } ] }, { "cell_type": "markdown", "source": [ "## Forward implícito\n", "* Puede consultar el blog [masterfinanciero.es](https://www.masterfinanciero.es/2010/10/forward-implicito.html)\n", "* Puede descargar el archivo de Excel [forward_implicito_01.xlsx](https://www.dropbox.com/s/7vbyj1cb9hxfqv9/forward_implicito_01.xlsx?dl=1)\n", "\n", "En el mercado están disponibles los siguientes bonos:\n", "* Bono A: Letra del Tesoro de duración un año y precio de adquisición 933 €\n", "* Bono B: Bono cupón explícito del 7% y duración 2 años que se adquiere con un descuento del 2% sobre el nominal.\n", "\n", "Se pide:\n", "* Determinar el tipo de interés forward implícito para el periodo que se inicia en t=1 y finaliza en t=2 años, $r_{12}$.\n", "* Calcular $r_{02}$\n", "* Calcular nuevamente $r_{12}$ utilizando para ello el valor de $r_{02}$ anteriormente calculado\n", "* Comprobar que el forward $r_{12}$ coincide por ambos métodos\n", "\n", "$$ (1+r_{02})^2 = (1+r_{01}) (1+r_{12}) $$" ], "metadata": { "id": "6vxj3IyOeimr" } }, { "cell_type": "code", "source": [ "import numpy_financial as npf\n", "import numpy as np\n", "\n", "############## MÉTODO 1 ##############\n", "\n", "# DATOS\n", "bonoA = np.array([-933, 1000, 0])\n", "bonoB = np.array([-98, 7, 107]) # ver los flujos de caja del archivo Excel\n", "\n", "# Bono C\n", "bonoC = np.array([0,0,0]) # inicializamos el ndarray\n", "bonoC = bonoA[0]*bonoB - bonoB[0]*bonoA\n", "print(f\"Bono C: {bonoC}\")\n", "\n", "# Forward r12\n", "r12 = npf.irr(bonoC)\n", "print(f\"MÉTODO 1: el forward r12 es {r12:.4%}\")\n", "\n", "############## MÉTODO 2 ##############\n", "\n", "# Bono D\n", "bonoD = np.array([0,0,0]) # inicializamos el ndarray\n", "bonoD = bonoA[1]*bonoB - bonoB[1]*bonoA\n", "print(f\"Bono D: {bonoD}\")\n", "\n", "# ETTI a dos años r02\n", "r02 = npf.irr(bonoD)\n", "print(f\"La ETTI a dos años es r02 = {r02:.4%}\")\n", "\n", "# TIR del Bono A (r01)\n", "r01 = npf.irr(bonoA)\n", "print(f\"La TIR del bono A es r01 = {r01:.4%}\")\n", "\n", "############## COMPROBACIÓN ##############\n", "\n", "# Comprobación r12 = r12_bis\n", "r12_bis = (1+r02)**2 / (1+r01) -1\n", "print(f\"MÉTODO 2: el forward r12 es {r12_bis:.4%}\")\n", "print(f\"La diferencia de r12 por ambos métodos es {abs(r12 - r12_bis)}\")" ], "metadata": { "id": "DLa4O2hJfddt", "outputId": "be8e4e4f-ba4b-4fd8-93dd-a07912699fd6", "colab": { "base_uri": "https://localhost:8080/" } }, "execution_count": 13, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Bono C: [ 0 91469 -99831]\n", "MÉTODO 1: el forward r12 es 9.1419%\n", "Bono D: [-91469 0 107000]\n", "La ETTI a dos años es r02 = 8.1571%\n", "La TIR del bono A es r01 = 7.1811%\n", "MÉTODO 2: el forward r12 es 9.1419%\n", "La diferencia de r12 por ambos métodos es 0.0\n" ] } ] }, { "cell_type": "markdown", "source": [ "### Cálculo de un tipo Forward $r_{23}$\n", "* Puede consultar el blog [Cálculo de un tipo Forward utilizando Solver](https://www.masterfinanciero.es/2010/10/calculo-de-un-tipo-forward-utilizando.html)\n", "* Puede descargar el archivo de Excel [forward_con_solver_01.xlsx](https://www.dropbox.com/s/6d9z41mimz5nyh0/forward_con_solver_01.xlsx?dl=1)\n", "\n", "En un mercado de renta fija cotizan los siguienes bonos:\n", "* Bono A: es un bono cupón cero a un año que se adquiere por 100 y se amortiza por 110\n", "* Bono B: es un bono cupón cero a dos años con TIR del 9% y precio de adquisición de 500 €\n", "* Bono C: es un bono cupón cero a tres años con TIR del 8% y nominal de 1.000 € \n", "\n", "Se pide:\n", "* Calcular el tipo de interés forward implícito en el mercado: r23" ], "metadata": { "id": "cqz3rt3u5zYG" } }, { "cell_type": "code", "source": [ "import numpy_financial as npf\n", "import numpy as np\n", "\n", "# DATOS\n", "bonoA = np.array([-100, 110, 0, 0])\n", "bonoB = np.array([-500, 0, 500*1.09**2, 0]) # la TIR del bono B es del 9%\n", "bonoC = np.array([-1000/1.08**3, 0, 0, 1000])\n", "\n", "print(f\"Bono A: {bonoA}\")\n", "print(f\"Bono B: {bonoB}\")\n", "print(f\"Bono C: {bonoC}\")\n", "\n", "############## MÉTODO 1 ##############\n", "\n", "bonoD = np.ndarray([0,0,0,0])\n", "bonoD = -bonoC[0] * bonoB + bonoB[0] * bonoC\n", "print(f\"Bono D: {bonoD}\")\n", "tirD = npf.irr(bonoD)\n", "print(f\"Método 1: el forward r23 es {tirD:.5%}\")\n", "\n", "############## MÉTODO 2 ##############\n", "r23 = (1+0.08)**3 / (1+0.09)**2 -1\n", "print(f\"Método 2: el forward r23 es {r23:.5%}\")" ], "metadata": { "id": "7ri_6-1l65Az", "outputId": "cfc90168-70a5-4afb-9548-ab79f76b5fb9", "colab": { "base_uri": "https://localhost:8080/" } }, "execution_count": 14, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Bono A: [-100 110 0 0]\n", "Bono B: [-500. 0. 594.05 0. ]\n", "Bono C: [-793.83224102 0. 0. 1000. ]\n", "Bono D: [ 0. 0. 471576.04277803 -500000. ]\n", "Método 1: el forward r23 es 6.02744%\n", "Método 2: el forward r23 es 6.02744%\n" ] } ] } ] }