{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Useful Functions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Find the maximum drawdown"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`PerformanceAnalytics` provides several functions to calculate the drawdowns. What I offered here is an alternative to `PerformanceAnalytics::table.Drawdowns`. The benefits of my solutoin are:\n",
    "\n",
    "- It's **1.89x** faster than `table.Drawdowns`.\n",
    "\n",
    "- It doesn't require the user to convert the input into a `zoo` or `xts` object, which is convenient if you're using `data.table`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create a Sample Data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The only inputs of our `drawdowns` function are 1) a return vector `ret` and 2) a date vector `date`. Note they should belong to the same stock.\n",
    "\n",
    "Let's generate these two variables."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "vscode": {
     "languageId": "r"
    }
   },
   "outputs": [],
   "source": [
    "set.seed(42)\n",
    "\n",
    "# Generate 100 returns with mean 0 and standard deviation 0.05\n",
    "ret = rnorm(100, mean=0, sd=0.05)\n",
    "\n",
    "# Generate 100 dates starting from 2010/1/1\n",
    "date = seq(as.Date(\"2010/1/1\"), by=\"day\", length.out=100)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### The `drawdowns` Function"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `drawdowns` below is a faster alternative to `PerformanceAnalytics`.\n",
    "\n",
    "**Inputs:**\n",
    "- `ret`: a vector of returns\n",
    "- `date`: a vector of dates\n",
    "- `top`: the number of largest drawdowns to be returned\n",
    "\n",
    "**Output:**\n",
    "A `data.table` with the following columns:\n",
    "- `start`: the start date of the drawdown\n",
    "- `trough`: the date of the trough\n",
    "- `end`: the last day of the darwdown (if new watermark hasn't been reached yet, it's the last day in the sample).\n",
    "- `depth`: the drawdown (percentage)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "vscode": {
     "languageId": "r"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<table class=\"dataframe\">\n",
       "<caption>A data.table: 2 × 4</caption>\n",
       "<thead>\n",
       "\t<tr><th scope=col>start</th><th scope=col>trough</th><th scope=col>end</th><th scope=col>depth</th></tr>\n",
       "\t<tr><th scope=col>&lt;date&gt;</th><th scope=col>&lt;date&gt;</th><th scope=col>&lt;date&gt;</th><th scope=col>&lt;dbl&gt;</th></tr>\n",
       "</thead>\n",
       "<tbody>\n",
       "\t<tr><td>2010-01-13</td><td>2010-02-16</td><td>2010-04-10</td><td>-0.49650974</td></tr>\n",
       "\t<tr><td>2010-01-02</td><td>2010-01-02</td><td>2010-01-03</td><td>-0.02823491</td></tr>\n",
       "</tbody>\n",
       "</table>\n"
      ],
      "text/latex": [
       "A data.table: 2 × 4\n",
       "\\begin{tabular}{llll}\n",
       " start & trough & end & depth\\\\\n",
       " <date> & <date> & <date> & <dbl>\\\\\n",
       "\\hline\n",
       "\t 2010-01-13 & 2010-02-16 & 2010-04-10 & -0.49650974\\\\\n",
       "\t 2010-01-02 & 2010-01-02 & 2010-01-03 & -0.02823491\\\\\n",
       "\\end{tabular}\n"
      ],
      "text/markdown": [
       "\n",
       "A data.table: 2 × 4\n",
       "\n",
       "| start &lt;date&gt; | trough &lt;date&gt; | end &lt;date&gt; | depth &lt;dbl&gt; |\n",
       "|---|---|---|---|\n",
       "| 2010-01-13 | 2010-02-16 | 2010-04-10 | -0.49650974 |\n",
       "| 2010-01-02 | 2010-01-02 | 2010-01-03 | -0.02823491 |\n",
       "\n"
      ],
      "text/plain": [
       "  start      trough     end        depth      \n",
       "1 2010-01-13 2010-02-16 2010-04-10 -0.49650974\n",
       "2 2010-01-02 2010-01-02 2010-01-03 -0.02823491"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "library(data.table)\n",
    "\n",
    "drawdowns <- function(ret, date, top=5) {\n",
    "    # This function calculates the drawdowns for a given return series\n",
    "    # Input:\n",
    "    #   ret: a vector of returns\n",
    "    #   date: a vector of dates\n",
    "    #   top: the number of largest drawdowns to be returned\n",
    "\n",
    "    input = data.table(date, ret)[order(date)]\n",
    "\n",
    "    # a drawdown is defined whenever the cumulative return is below the previous peak\n",
    "    drawdowns_raw = input[, {\n",
    "        ret_cum=cumprod(1 + ret)\n",
    "        ret_cummax=cummax(c(1, ret_cum))[-1]\n",
    "        drawdowns=ret_cum/ret_cummax - 1\n",
    "        list(date, ret, ret_cum, ret_cummax, drawdowns)\n",
    "    }]\n",
    "\n",
    "    # print(drawdowns_raw)\n",
    "\n",
    "    # find the largest drawdowns\n",
    "    drawdowns = drawdowns_raw[, ':='(grp = rleid(drawdowns<0))\n",
    "        ][drawdowns<0, \n",
    "        .(start=date[1], trough=date[which.min(drawdowns)],\n",
    "          end=date[.N], depth=drawdowns[which.min(drawdowns)]),\n",
    "        keyby=.(grp)\n",
    "        ][order(depth)]\n",
    "\n",
    "    # return the top drawdowns\n",
    "    top = fifelse(top > nrow(drawdowns), nrow(drawdowns), top)\n",
    "    drawdowns = drawdowns[1:top][, ':='(grp=NULL)]\n",
    "    \n",
    "    return(drawdowns[])\n",
    "}\n",
    "\n",
    "drawdowns(ret, date, top=2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we use `PerformanceAnalytics::table.Drawdowns`, the code and result are offered below. As you can see, the result is the same."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "vscode": {
     "languageId": "r"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<table class=\"dataframe\">\n",
       "<caption>A data.frame: 2 × 3</caption>\n",
       "<thead>\n",
       "\t<tr><th scope=col>From</th><th scope=col>Trough</th><th scope=col>Depth</th></tr>\n",
       "\t<tr><th scope=col>&lt;date&gt;</th><th scope=col>&lt;date&gt;</th><th scope=col>&lt;dbl&gt;</th></tr>\n",
       "</thead>\n",
       "<tbody>\n",
       "\t<tr><td>2010-01-13</td><td>2010-02-16</td><td>-0.4965</td></tr>\n",
       "\t<tr><td>2010-01-02</td><td>2010-01-02</td><td>-0.0282</td></tr>\n",
       "</tbody>\n",
       "</table>\n"
      ],
      "text/latex": [
       "A data.frame: 2 × 3\n",
       "\\begin{tabular}{lll}\n",
       " From & Trough & Depth\\\\\n",
       " <date> & <date> & <dbl>\\\\\n",
       "\\hline\n",
       "\t 2010-01-13 & 2010-02-16 & -0.4965\\\\\n",
       "\t 2010-01-02 & 2010-01-02 & -0.0282\\\\\n",
       "\\end{tabular}\n"
      ],
      "text/markdown": [
       "\n",
       "A data.frame: 2 × 3\n",
       "\n",
       "| From &lt;date&gt; | Trough &lt;date&gt; | Depth &lt;dbl&gt; |\n",
       "|---|---|---|\n",
       "| 2010-01-13 | 2010-02-16 | -0.4965 |\n",
       "| 2010-01-02 | 2010-01-02 | -0.0282 |\n",
       "\n"
      ],
      "text/plain": [
       "  From       Trough     Depth  \n",
       "1 2010-01-13 2010-02-16 -0.4965\n",
       "2 2010-01-02 2010-01-02 -0.0282"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "suppressMessages({library(PerformanceAnalytics)})\n",
    "\n",
    "inputs = zoo(ret, order.by=date)\n",
    "table.Drawdowns(inputs, top=2)[, c('From', 'Trough', 'Depth')]"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "R",
   "language": "R",
   "name": "ir"
  },
  "language_info": {
   "codemirror_mode": "r",
   "file_extension": ".r",
   "mimetype": "text/x-r-source",
   "name": "R",
   "pygments_lexer": "r",
   "version": "4.3.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}