{ "cells": [ { "cell_type": "markdown", "id": "3216dcbe", "metadata": {}, "source": [ "
" ] }, { "cell_type": "code", "execution_count": 1, "id": "2348156b", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import yfinance as yf\n", "import warnings\n", "warnings.filterwarnings(\"ignore\")" ] }, { "cell_type": "markdown", "id": "054e4261", "metadata": {}, "source": [ "## Retrieve historical stock prices for selected assets" ] }, { "cell_type": "markdown", "id": "6dc9ad89-8631-4802-821b-399c956158bd", "metadata": {}, "source": [ "We start by collecting historical stock prices for a set of specified assets. We will use the `yfinance` library to download this data." ] }, { "cell_type": "code", "execution_count": 2, "id": "65f895d0", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "[*********************100%%**********************] 5 of 5 completed\n" ] } ], "source": [ "prices = yf.download([\"FDN\", \"FTXL\", \"FXD\", \"FXR\", \"HDEF\"], start=\"2020-01-01\")" ] }, { "cell_type": "markdown", "id": "b258dbd9-5a22-46b4-ae2c-ce99a23291ec", "metadata": {}, "source": [ "We use the `yfinance` library to download historical price data for five different assets, starting from January 1, 2020. This data includes all available prices up to the current date. The data is returned in a structured format, with separate columns for different types of prices, such as open, high, low, close, and adjusted close. We're interested in the adjusted close prices, which account for corporate actions like dividends and stock splits." ] }, { "cell_type": "markdown", "id": "dbeb7368", "metadata": {}, "source": [ "## Calculate daily returns for each asset" ] }, { "cell_type": "markdown", "id": "79820113-91f4-49f1-97cf-17ebd716c7e8", "metadata": {}, "source": [ "Next, we calculate the daily returns for each asset. This helps us understand how the price of each asset changes from one day to the next." ] }, { "cell_type": "code", "execution_count": 4, "id": "d61f22ee", "metadata": {}, "outputs": [], "source": [ "returns = (\n", " prices[\"Adj Close\"]\n", " .pct_change()\n", " .dropna()\n", ")" ] }, { "cell_type": "markdown", "id": "fa2b88c8-f9c7-43e3-9d5d-c36c50225c67", "metadata": {}, "source": [ "We calculate the daily returns by taking the percentage change of the adjusted close prices from one day to the next. The `pct_change()` function is used to compute these changes. We drop any missing values that may arise from calculating percentage changes, particularly at the start of the dataset. The result is a new dataset where each value represents the daily return of an asset expressed as a percentage." ] }, { "cell_type": "markdown", "id": "63911f78", "metadata": {}, "source": [ "## Determine expected returns and covariance matrix" ] }, { "cell_type": "markdown", "id": "5267166d-e2c1-45b0-bda3-6f0f340a0f2f", "metadata": {}, "source": [ "We now compute the expected returns for each asset and the covariance matrix of the returns. The expected return gives us an average sense of how much we can expect each asset to return. The covariance matrix helps us understand how the returns of the different assets move in relation to each other." ] }, { "cell_type": "code", "execution_count": 5, "id": "754a1cb1-4498-4a8a-8a08-b6b3069c2ddd", "metadata": {}, "outputs": [], "source": [ "expected_returns = np.mean(returns, axis=0)\n", "cov_matrix = np.cov(returns, rowvar=False)" ] }, { "cell_type": "markdown", "id": "c6176ff7-22df-4e56-9c12-f9a1bbccf300", "metadata": {}, "source": [ "We calculate the expected returns using the mean of the daily returns for each asset. This gives us a single number for each asset representing its average daily return over the entire period. The covariance matrix is computed using `np.cov`, which takes the returns data and calculates how the returns of different assets change together. The result is a matrix where each element represents the covariance between a pair of assets, helping us understand their return correlations." ] }, { "cell_type": "markdown", "id": "9f2556d4", "metadata": {}, "source": [ "## Evaluate the portfolio's risk through variance and standard deviation" ] }, { "cell_type": "markdown", "id": "b09aac17-c051-4214-a4ee-e38bbab9fc2e", "metadata": {}, "source": [ "Finally, we define a portfolio with equal weights for each asset and calculate its variance and standard deviation. These metrics will help us assess the risk associated with the portfolio." ] }, { "cell_type": "code", "execution_count": 6, "id": "c961c89e", "metadata": {}, "outputs": [], "source": [ "weights = np.array([0.2] * 5)\n", "portfolio_variance = np.dot(weights.T, np.dot(cov_matrix, weights))\n", "portfolio_std_dev = np.sqrt(portfolio_variance) * np.sqrt(252)" ] }, { "cell_type": "markdown", "id": "5872f502-98b0-436a-bf0d-6e635bf8979d", "metadata": {}, "source": [ "We define equal weights of 0.2 for each asset, assuming we want to allocate the same proportion of our investment to each. The portfolio variance is calculated using a mathematical formula that combines the weights and the covariance matrix. This calculation results in a single value representing the total risk of the portfolio based on the variance of its assets. To get the annualized standard deviation, we take the square root of the portfolio variance and multiply it by the square root of 252, the typical number of trading days in a year. The standard deviation provides a measure of how much the portfolio's return might fluctuate annually." ] }, { "cell_type": "markdown", "id": "ec9e6505", "metadata": {}, "source": [ "## Your next steps" ] }, { "cell_type": "markdown", "id": "3996c26e-d565-4724-8128-d6ce7672bf74", "metadata": {}, "source": [ "Try modifying the weight distribution among the assets to see how it affects the portfolio's risk. You can adjust the weights in the `weights` array, making some assets more dominant than others. Observe how changes in asset allocation impact the portfolio's variance and standard deviation, allowing you to explore different risk-return profiles. Experimenting with different weights helps in understanding the dynamics of portfolio optimization." ] }, { "cell_type": "markdown", "id": "6928a33e", "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" }, "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.13" } }, "nbformat": 4, "nbformat_minor": 5 }