{ "cells": [ { "cell_type": "markdown", "id": "6ae95e22", "metadata": {}, "source": [ "
" ] }, { "cell_type": "markdown", "id": "d03b11d6", "metadata": {}, "source": [ "This code downloads historical price data for specific stocks and calculates a portfolio's performance. It uses Yahoo Finance data to get adjusted close prices for QQQ, AAPL, and AMZN. The code constructs a simple portfolio of equal shares in AAPL and AMZN, computes the portfolio's value, daily returns, and cumulative returns over time. It then compares the portfolio's cumulative returns to a benchmark (QQQ). Finally, it calculates the information ratio to evaluate the portfolio's performance relative to the benchmark." ] }, { "cell_type": "code", "execution_count": null, "id": "df51ef5b", "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "import yfinance as yf" ] }, { "cell_type": "markdown", "id": "d1365087", "metadata": {}, "source": [ "Download historical price data for QQQ, AAPL, and AMZN from Yahoo Finance" ] }, { "cell_type": "code", "execution_count": null, "id": "6c4473af", "metadata": {}, "outputs": [], "source": [ "data = yf.download([\"QQQ\", \"AAPL\", \"AMZN\"], start=\"2020-01-01\", end=\"2022-07-31\")" ] }, { "cell_type": "markdown", "id": "a22d784e", "metadata": {}, "source": [ "Extract adjusted close prices for the downloaded data" ] }, { "cell_type": "code", "execution_count": null, "id": "ab04ef0d", "metadata": {}, "outputs": [], "source": [ "closes = data['Adj Close']\n", "benchmark_returns = closes.QQQ.pct_change()" ] }, { "cell_type": "markdown", "id": "7788fe03", "metadata": {}, "source": [ "Construct a simple portfolio with equal shares of AAPL and AMZN" ] }, { "cell_type": "code", "execution_count": null, "id": "3ac0ea69", "metadata": {}, "outputs": [], "source": [ "aapl_position = closes.AAPL * 50\n", "amzn_position = closes.AMZN * 50" ] }, { "cell_type": "markdown", "id": "82e0e793", "metadata": {}, "source": [ "Compute the portfolio value over time by summing the positions" ] }, { "cell_type": "code", "execution_count": null, "id": "3e5c9614", "metadata": {}, "outputs": [], "source": [ "portfolio_value = aapl_position + amzn_position" ] }, { "cell_type": "markdown", "id": "75f062eb", "metadata": {}, "source": [ "Calculate the portfolio's daily profit and loss (PnL)" ] }, { "cell_type": "code", "execution_count": null, "id": "98e59e8c", "metadata": {}, "outputs": [], "source": [ "portfolio_pnl = (\n", " (aapl_position - aapl_position.shift()) \n", " + (amzn_position - amzn_position.shift())\n", ")" ] }, { "cell_type": "markdown", "id": "410af899", "metadata": {}, "source": [ "Compute the portfolio's daily return by dividing PnL by the portfolio value" ] }, { "cell_type": "code", "execution_count": null, "id": "e17de052", "metadata": {}, "outputs": [], "source": [ "portfolio_returns = (portfolio_pnl / portfolio_value)\n", "portfolio_returns.name = \"Port\"" ] }, { "cell_type": "markdown", "id": "6349bff8", "metadata": {}, "source": [ "Create cumulative returns for both the portfolio and the benchmark" ] }, { "cell_type": "code", "execution_count": null, "id": "ea4a9b96", "metadata": {}, "outputs": [], "source": [ "portfolio_cumulative_returns = (portfolio_returns.fillna(0.0) + 1).cumprod()\n", "benchmark_cumulative_returns = (benchmark_returns.fillna(0.0) + 1).cumprod()" ] }, { "cell_type": "markdown", "id": "1382ec20", "metadata": {}, "source": [ "Plot the cumulative returns of the portfolio against the benchmark" ] }, { "cell_type": "code", "execution_count": null, "id": "9ba13165", "metadata": {}, "outputs": [], "source": [ "portfolio_cumulative_returns = (portfolio_returns.fillna(0.0) + 1).cumprod()\n", "benchmark_cumulative_returns = (benchmark_returns.fillna(0.0) + 1).cumprod()" ] }, { "cell_type": "code", "execution_count": null, "id": "9e6d8de3", "metadata": { "lines_to_next_cell": 1 }, "outputs": [], "source": [ "pd.concat([portfolio_cumulative_returns, benchmark_cumulative_returns], axis=1).plot()" ] }, { "cell_type": "code", "execution_count": null, "id": "8454d5ed", "metadata": { "lines_to_next_cell": 1 }, "outputs": [], "source": [ "def information_ratio(portfolio_returns, benchmark_returns):\n", " \"\"\"\n", " Determines the information ratio of a strategy.\n", " \n", " Parameters\n", " ----------\n", " portfolio_returns : pd.Series or np.ndarray\n", " Daily returns of the strategy, noncumulative.\n", " benchmark_returns : int, float\n", " Daily returns of the benchmark or factor, noncumulative.\n", "\n", " Returns\n", " -------\n", " information_ratio : float\n", "\n", " Note\n", " -----\n", " See https://en.wikipedia.org/wiki/Information_ratio for more details.\n", " \"\"\"\n", " \n", " # Calculate active return by subtracting benchmark returns from portfolio returns\n", " active_return = portfolio_returns - benchmark_returns\n", "\n", " # Calculate tracking error as the standard deviation of active returns\n", " tracking_error = active_return.std()\n", "\n", " # Return the information ratio, which is the mean active return divided by the tracking error\n", " return active_return.mean() / tracking_error" ] }, { "cell_type": "markdown", "id": "7bd6fa3a", "metadata": {}, "source": [ "Calculate the information ratio of the portfolio relative to the benchmark" ] }, { "cell_type": "code", "execution_count": null, "id": "6960c140", "metadata": {}, "outputs": [], "source": [ "information_ratio(portfolio_returns, benchmark_returns)" ] }, { "cell_type": "markdown", "id": "e225688c", "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 }