ml-finance-python

python scripts for finance machine learning

git clone https://9o.is/git/ml-finance-python.git

lab_202.ipynb

(24367B)


      1 {
      2  "cells": [
      3   {
      4    "cell_type": "markdown",
      5    "metadata": {},
      6    "source": [
      7     "# Sharpe Style Analysis\n",
      8     "\n",
      9     "Sharpe Style Analysis is an elegant and simple decomposition exercise similar to what we did in the previous lab session, with the added constraint that the coefficients are all positive and add to 1.\n",
     10     "\n",
     11     "Therefore, the coefficients of performing style analysis on the observed return of a manager can be interpreted as weights in a portfolio of building blocks which together, _mimic_ that return series. The exercise can reveal drifts in a manager's style as well as provide insight into what the manager is likely doing to obtain the returns.\n",
     12     "\n",
     13     "\n",
     14     "# Performing Sharpe Style Analysis\n",
     15     "\n",
     16     "The key to obtaining the weights is our old friend, the quadriatic optimizer. We are asking the optimizer to find the weights that minimizes the square of the difference between the observed series and the returns of a benchmark portfolio that holds the explanatory building blocks in those same weights. This is equivalent to minimizing the _tracking error_ between the two return series.\n",
     17     "\n",
     18     "The code to implement this is a very slight modification of the `minimize_vol` we have previously implemented:\n",
     19     "\n",
     20     "```python                         \n",
     21     "def style_analysis(dependent_variable, explanatory_variables):\n",
     22     "    \"\"\"\n",
     23     "    Returns the optimal weights that minimizes the Tracking error between\n",
     24     "    a portfolio of the explanatory variables and the dependent variable\n",
     25     "    \"\"\"\n",
     26     "    n = explanatory_variables.shape[1]\n",
     27     "    init_guess = np.repeat(1/n, n)\n",
     28     "    bounds = ((0.0, 1.0),) * n # an N-tuple of 2-tuples!\n",
     29     "    # construct the constraints\n",
     30     "    weights_sum_to_1 = {'type': 'eq',\n",
     31     "                        'fun': lambda weights: np.sum(weights) - 1\n",
     32     "    }\n",
     33     "    solution = minimize(portfolio_tracking_error, init_guess,\n",
     34     "                       args=(dependent_variable, explanatory_variables,), method='SLSQP',\n",
     35     "                       options={'disp': False},\n",
     36     "                       constraints=(weights_sum_to_1,),\n",
     37     "                       bounds=bounds)\n",
     38     "    weights = pd.Series(solution.x, index=explanatory_variables.columns)\n",
     39     "    return weights\n",
     40     "```\n",
     41     "\n",
     42     "The Objective function is a very simple one-liner\n",
     43     "\n",
     44     "```python\n",
     45     "def portfolio_tracking_error(weights, ref_r, bb_r):\n",
     46     "    \"\"\"\n",
     47     "    returns the tracking error between the reference returns\n",
     48     "    and a portfolio of building block returns held with given weights\n",
     49     "    \"\"\"\n",
     50     "    return tracking_error(ref_r, (weights*bb_r).sum(axis=1))\n",
     51     "```"
     52    ]
     53   },
     54   {
     55    "cell_type": "code",
     56    "execution_count": 1,
     57    "metadata": {},
     58    "outputs": [],
     59    "source": [
     60     "import numpy as np\n",
     61     "import pandas as pd\n",
     62     "\n",
     63     "import edhec_risk_kit_202 as erk\n",
     64     "\n",
     65     "%load_ext autoreload\n",
     66     "%autoreload 2\n"
     67    ]
     68   },
     69   {
     70    "cell_type": "code",
     71    "execution_count": 2,
     72    "metadata": {},
     73    "outputs": [],
     74    "source": [
     75     "ind = erk.get_ind_returns()[\"2000\":]"
     76    ]
     77   },
     78   {
     79    "cell_type": "markdown",
     80    "metadata": {},
     81    "source": [
     82     "Let's construct a manager that invests in 30% Beer, 50% in Smoke and 20% in other things that have an average return of 0% and an annualized vol of 15%"
     83    ]
     84   },
     85   {
     86    "cell_type": "code",
     87    "execution_count": 3,
     88    "metadata": {},
     89    "outputs": [],
     90    "source": [
     91     "mgr_r = 0.3*ind[\"Beer\"] + .5*ind[\"Smoke\"] + 0.2*np.random.normal(scale=0.15/(12**.5), size=ind.shape[0])"
     92    ]
     93   },
     94   {
     95    "cell_type": "markdown",
     96    "metadata": {},
     97    "source": [
     98     "Now, assume we knew absolutely nothing about this manager and all we observed was the returns. How could we tell what she was invested in?"
     99    ]
    100   },
    101   {
    102    "cell_type": "code",
    103    "execution_count": 4,
    104    "metadata": {},
    105    "outputs": [],
    106    "source": [
    107     "weights = erk.style_analysis(mgr_r, ind)*100"
    108    ]
    109   },
    110   {
    111    "cell_type": "code",
    112    "execution_count": 5,
    113    "metadata": {},
    114    "outputs": [
    115     {
    116      "data": {
    117       "text/plain": [
    118        "<matplotlib.axes._subplots.AxesSubplot at 0x7fcec1f82e80>"
    119       ]
    120      },
    121      "execution_count": 5,
    122      "metadata": {},
    123      "output_type": "execute_result"
    124     },
    125     {
    126      "data": {
    127       "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAEUCAYAAAA7l80JAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvOIA7rQAAEhpJREFUeJzt3XmwZGV9xvHncQYCuAGZK07YZlIiYKIsXigSLGOG4BKNkHLX6JiQjElIJHEL0VQUjQnG3bhOBDOVGBZFAhLLgAgSS4MMCA5mRBDRUFDMsIi4gTM++eOcC831znTfe7v73Pub76fqVvdZes7vVE8/ffo973uOkwgAsPg9pOsCAADDQaADQBEEOgAUQaADQBEEOgAUQaADQBEEOgAUQaADQBFLB1nJ9k2S7pG0VdKWJJO295R0lqQVkm6S9Pwkd42mTABAP7M5Qv/NJIcmmWynT5Z0cZIDJF3cTgMAOuJBhv63R+iTSW7vmXedpKckudX2ckmXJjlwe//OsmXLsmLFivlVDAA7mCuvvPL2JBP91huoyUVSJF1oO5I+kmStpL2S3CpJbag/qt8/smLFCq1fv37ATQIAJMn2dwZZb9BAPzrJLW1oX2T7G7MoZI2kNZK03377DfoyAMAsDdSGnuSW9nGTpHMlHSnptrapRe3jpm28dm2SySSTExN9fzEAAOaob6Dbfqjth089l/RUSddKOl/S6na11ZLOG1WRAID+Bmly2UvSuban1v/3JJ+1fYWks22fIOm7kp43ujIBAP30DfQkN0o6ZIb5d0g6ZhRFAQBmj5GiAFAEgQ4ARRDoAFDEoP3QO7Xi5P8c6/ZuOvWZY90eAAwDR+gAUASBDgBFEOgAUASBDgBFEOgAUASBDgBFEOgAUASBDgBFEOgAUASBDgBFEOgAUASBDgBFEOgAUASBDgBFEOgAUASBDgBFEOgAUASBDgBFEOgAUASBDgBFEOgAUASBDgBFEOgAUASBDgBFEOgAUASBDgBFEOgAUASBDgBFEOgAUASBDgBFDBzotpfY/qrtC9rplbYvt3297bNs7zy6MgEA/czmCP0kSRt7pt8m6d1JDpB0l6QThlkYAGB2Bgp02/tIeqakj7bTlrRK0ifbVdZJOn4UBQIABjPoEfp7JL1O0s/a6V+U9L0kW9rpmyXtPeTaAACz0DfQbT9L0qYkV/bOnmHVbOP1a2yvt71+8+bNcywTANDPIEfoR0t6tu2bJJ2ppqnlPZJ2t720XWcfSbfM9OIka5NMJpmcmJgYQskAgJn0DfQkf51knyQrJL1Q0ueTvETSJZKe2662WtJ5I6sSANDXfPqh/5WkV9m+QU2b+mnDKQkAMBdL+6/ygCSXSrq0fX6jpCOHXxIAYC4YKQoARRDoAFAEgQ4ARRDoAFAEgQ4ARRDoAFAEgQ4ARRDoAFAEgQ4ARRDoAFAEgQ4ARRDoAFAEgQ4ARRDoAFAEgQ4ARRDoAFAEgQ4ARRDoAFAEgQ4ARRDoAFAEgQ4ARRDoAFAEgQ4ARSztugBIetMjx7itu8e3LQBjxRE6ABRBoANAEQQ6ABRBoANAEQQ6ABRBoANAEQQ6ABRBoANAEQQ6ABRBoANAEX0D3fYutr9i+xrbX7d9Sjt/pe3LbV9v+yzbO4++XADAtgxyhH6vpFVJDpF0qKSn2z5K0tskvTvJAZLuknTC6MoEAPTTN9DT+EE7uVP7F0mrJH2ynb9O0vEjqRAAMJCB2tBtL7F9taRNki6S9C1J30uypV3lZkl7j6ZEAMAgBgr0JFuTHCppH0lHSjp4ptVmeq3tNbbX216/efPmuVcKANiuWfVySfI9SZdKOkrS7ranrqe+j6RbtvGatUkmk0xOTEzMp1YAwHYM0stlwvbu7fNdJf2WpI2SLpH03Ha11ZLOG1WRAID+Brlj0XJJ62wvUfMFcHaSC2z/r6Qzbf+dpK9KOm2EdQIA+ugb6Em+JumwGebfqKY9HQCwADBSFACKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoIi+gW57X9uX2N5o++u2T2rn72n7ItvXt497jL5cAMC2DHKEvkXSq5McLOkoSSfafpykkyVdnOQASRe30wCAjvQN9CS3JrmqfX6PpI2S9pZ0nKR17WrrJB0/qiIBAP3Nqg3d9gpJh0m6XNJeSW6VmtCX9KhhFwcAGNzAgW77YZLOkfQXSb4/i9etsb3e9vrNmzfPpUYAwAAGCnTbO6kJ848n+VQ7+zbby9vlyyVtmum1SdYmmUwyOTExMYyaAQAzGKSXiyWdJmljknf1LDpf0ur2+WpJ5w2/PADAoJYOsM7Rkl4qaYPtq9t5r5d0qqSzbZ8g6buSnjeaEgEAg+gb6Em+KMnbWHzMcMsBAMwVI0UBoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCKINABoAgCHQCK6Bvotk+3vcn2tT3z9rR9ke3r28c9RlsmAKCfQY7Q/0XS06fNO1nSxUkOkHRxOw0A6FDfQE9ymaQ7p80+TtK69vk6SccPuS4AwCzNtQ19ryS3SlL7+KjhlQQAmIuRnxS1vcb2etvrN2/ePOrNAcAOa66Bfpvt5ZLUPm7a1opJ1iaZTDI5MTExx80BAPqZa6CfL2l1+3y1pPOGUw4AYK4G6bZ4hqQvSzrQ9s22T5B0qqRjbV8v6dh2GgDQoaX9Vkjyom0sOmbItQAA5oGRogBQBIEOAEUQ6ABQBIEOAEUQ6ABQBIEOAEUQ6ABQBIEOAEUQ6ABQBIEOAEUQ6ABQBIEOAEUQ6ABQBIEOAEX0vXwuMB+PX/f4sW5vw+oNY90esJBwhA4ARRDoAFAEgQ4ARRDoAFAEJ0WBedh40MFj3d7B39g41u1hceEIHQCKINABoAgCHQCKoA0dwDZ94I8/P9btnfjhVWPdXjUcoQNAEQQ6ABRBoANAEQQ6ABTBSVEAO6x3vuBZY93eq8+6YKT/PkfoAFAEgQ4ARRDoAFAEgQ4ARRDoAFDEvALd9tNtX2f7BtsnD6soAMDszTnQbS+R9AFJz5D0OEkvsv24YRUGAJid+RyhHynphiQ3JrlP0pmSjhtOWQCA2ZpPoO8t6f96pm9u5wEAOuAkc3uh/TxJT0vyh+30SyUdmeTPp623RtKadvJASdfNvdxZWybp9jFub9wq71/lfZPYv8Vu3Pu3f5KJfivNZ+j/zZL27ZneR9It01dKslbS2nlsZ85sr08y2cW2x6Hy/lXeN4n9W+wW6v7Np8nlCkkH2F5pe2dJL5R0/nDKAgDM1pyP0JNssf1nkv5L0hJJpyf5+tAqAwDMyryutpjkM5I+M6RaRqGTpp4xqrx/lfdNYv8WuwW5f3M+KQoAWFgY+g8ARRDoAFAEgb6I2H6I7V/vug4AC1O5NnTbu0raL8k4BzCNje0vJ/m1rusYJtuHb295kqvGVQtmz/ae21ue5M5x1bKjKxXotn9H0jsk7Zxkpe1DJb05ybM7Lm1obJ8i6WuSPpUib57tS9qnu0ialHSNJEt6gqTLkzypq9qGyfZjJb1W0v7q6WGWZFVnRQ2B7W9Lipr3bLok+eUxlzRUtj+tZv9mtJDypVqgXylplaRLkxzWzvtakid0W9nw2L5H0kMlbZX0YzUfoiR5RKeFDYHtMyW9NcmGdvpXJb0mycs7LWxIbF8j6cOSrlTz/kmSklzZWVHoy/ZvbG95ki+Mq5Z+5tUPfQHakuRue6YDhRqSPLzrGkbooKkwl6Qk17a/sqrYkuRDXRcxbLYPSvKNbTWdLfYms4UU2P1UC/Rrbb9Y0hLbB0h6paQvdVzTULn5tnqJpJVJ3mJ7X0nLk3yl49KGYaPtj0r6NzU/cX9P0sZuS5q/njbmT9v+U0nnSrp3anmBNuZXqbkA3ztnWBY1v5oXLdtnJ3m+7Q2aoellIbUAVGty2U3SGyQ9tZ11oaS3JPlJd1UNl+0PSfqZpFVJDra9h6QLkxzRcWnzZnsXSX8i6cntrMskfWixv3/V25in2N5l+ns107zFxvbyJLfa3n+m5Um+M+6atqVaoK9IctO0eUckuaKjkobO9lVJDrf91Z7zBNckOaTr2oahvdDbgWoC8LokP+24pKGpGnhTpv5v9puH0anWD/1Ttu+/yYbtJ0s6vcN6RuGn7e3/Ikm2J9QcsS96tp8i6XpJ75f0QUnfbN/DKmZq/lv0TYK2H237iZJ2tX14z99TJO3WcXlDY/so21fY/oHt+2xvtf39ruvqVa0N/RWS/qPtvni4pL+X9NvdljR071PTBruX7bdKeq6kv+m2pKF5p6SnTo0haLv5nSHpiZ1WNU+2H63mbl672j5MDzS9PEI1Au9pkl6u5p4I7+iZf4+k13dR0Ii8X81lwj+hpnvtyyQ9ptOKpikV6EmusP1KNW3nP5F0bJLNHZc1VEk+3nbPPEZNMByfZNGfOGzt1DsgLMk3be/UZUFD0ht47+qZXyXwlkm6oP2Tml+PmyV9Mcm3O6tqBJLcYHtJkq2SPmZ7Qf3CKhHoM3T8303S3ZJOs72gOv4PyTJJP0ryMdsTtlcW+eCst32apH9tp1+ips/2opZknaR1tp+T5Jyu6xmBh80wb39Jb7D9piRnjrugEflRe47natv/KOlWNWNCFowSJ0UXU8f/+bL9RjU/9w5M8ljbvyTpE0mO7ri0ebP9C5JOlPQkNb8+LpP0wST3bveFC5ztV21veZJ3bW/5YtV21/xclZOibS+X2yTtLOkvJT1S0geSfKvTwnqUOELvDWzbe0ma6sL3lSSbuqlqZH5X0mGSrpKkJLfYLjHYKMm9tt8v6SLV6uVS4v2ZrSR3utYov+OTvFdNc+4pkmT7JEnv7bSqHiUCfYrt50t6u6RL1Rzh/ZPt1yb5ZKeFDdd9SWJ7qpfLgvrJNx9tr4h1km5S8/7ta3t1ksu6rGu+kpzSdQ1dsL1K0l1d1zFEq/Xz4f3yGeZ1plSgqxlUdMTUUXnbpe9zkioF+tm2PyJpd9t/JOkPJP1zxzUNS9VeLu/b3vIkrxxXLaOwjRGUe0q6RU1PkEXN9oskvVjSStvn9yx6uKQ7uqlqZtUC/SHTmljuULG+9kneYftYSd9XMwDnb5Nc1HFZw1K1l0vvid1TJL2xq0JG5FnTpiPpjiQ/7KKYEfiSmhOgy/Tgyxvco+bKpwtGiZOiU2y/Xc0lV89oZ71A0oYkr+uuqtGxvUzNB6fEm2j7dDVh0NvLZWmS3++uquHqHeGLxa0d4PfCJB/vupYppQJdkmw/R9LRantJJDm345KGwvZRkk6VdKekt6gJvWVqfoG8LMlnOyxvKKr2cunFUPjFx/Yj1Py/3FvS+WpO2p+o5tr2Vyc5rsPyHqRcoEv3vwG9NxBY7Fezk+31agahPFLSWknPSPI/tg+SdMZiPuqzvV+S73ZdxzgQ6IuP7fPUnNz9spoBfXuo6bp4UpKru6xtulKBbvsVkt6s5sYPP9MDN39Y9Fezs311kkPb5xuTHNyzbFH/jO8NOdvnJHlO1zUNk5ubkkx90HaT9KOpRSpyc5LKbG9I8vj2+RJJt6u5zeU93Vb286qdFH2NpF9JcnvXhYxA7wW4fjxt2WL/Vu7tq7zov3ynK35Tkh3B/WMhkmy1/e2FGOZSvUD/lh44+qnmkPbKblZzkaepq7xZzb04F7Ns4zmwEBwy7fO2a89ncUH9wqrW5HKYpI9JulwPviPMou7nW53trZJ+qPbDIpokgDmpdoT+EUmfl7RBRa4RviNIsqTrGoAKqgX6liTbvRASAFRVahSlpEtsr7G93PaeU39dFwUA41CtDX3qmuAP2qkK3RYBoJ8SR+i2j7D96CQrk6xUc72Ma9XcQWWy2+oAYDxKBLqak6H3SfffGPof1FyG9W41oyoBoLwqJ0WX9Azvf4Gkte2tvs6xvaCG5gLAqFQ5Ql9ie+rL6Rg1XRenVPnSAoDtqhJ2Z0j6gu3b1QyL/29Jsv0YNc0uAFBemV4u7eVll0u6cOrC+u0dbx6W5KpOiwOAMSgT6ACwo6vShg4AOzwCHQCKINABoAgCHQCKINABoIj/B/q/EvVwuco2AAAAAElFTkSuQmCC\n",
    128       "text/plain": [
    129        "<Figure size 432x288 with 1 Axes>"
    130       ]
    131      },
    132      "metadata": {
    133       "needs_background": "light"
    134      },
    135      "output_type": "display_data"
    136     }
    137    ],
    138    "source": [
    139     "weights.sort_values(ascending=False).head(6).plot.bar()"
    140    ]
    141   },
    142   {
    143    "cell_type": "markdown",
    144    "metadata": {},
    145    "source": [
    146     "Contrast this to the results of a regression. Because the model is in fact very true (i.e. we really did construct the manager's returns out of the building blocks), the results are remarkably accurate. However, the negative coefficients are hard to intepret and in real-life data, those will be much larger. However when it works well, such as in this artificial example here, the results can be very accurate."
    147    ]
    148   },
    149   {
    150    "cell_type": "code",
    151    "execution_count": 6,
    152    "metadata": {},
    153    "outputs": [
    154     {
    155      "data": {
    156       "text/plain": [
    157        "Hshld   -3.454557\n",
    158        "Steel   -2.279649\n",
    159        "Chems   -2.003106\n",
    160        "Oil     -1.485098\n",
    161        "Meals   -1.411059\n",
    162        "dtype: float64"
    163       ]
    164      },
    165      "execution_count": 6,
    166      "metadata": {},
    167      "output_type": "execute_result"
    168     }
    169    ],
    170    "source": [
    171     "coeffs = erk.regress(mgr_r, ind).params*100\n",
    172     "coeffs.sort_values().head()"
    173    ]
    174   },
    175   {
    176    "cell_type": "markdown",
    177    "metadata": {},
    178    "source": [
    179     "Negative 4.5% in Household?"
    180    ]
    181   },
    182   {
    183    "cell_type": "code",
    184    "execution_count": 7,
    185    "metadata": {},
    186    "outputs": [
    187     {
    188      "data": {
    189       "text/plain": [
    190        "<matplotlib.axes._subplots.AxesSubplot at 0x7fcec1e664a8>"
    191       ]
    192      },
    193      "execution_count": 7,
    194      "metadata": {},
    195      "output_type": "execute_result"
    196     },
    197     {
    198      "data": {
    199       "image/png": "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\n",
    200       "text/plain": [
    201        "<Figure size 432x288 with 1 Axes>"
    202       ]
    203      },
    204      "metadata": {
    205       "needs_background": "light"
    206      },
    207      "output_type": "display_data"
    208     }
    209    ],
    210    "source": [
    211     "coeffs.sort_values(ascending=False).head(6).plot.bar()"
    212    ]
    213   },
    214   {
    215    "cell_type": "markdown",
    216    "metadata": {},
    217    "source": [
    218     "## Style Drift: Time Varying Exposures using Style Anaylsis\n",
    219     "\n",
    220     "One of the most common ways in which Sharpe Style Analysis can be used is to measure style drift. If you run the style analysis function over a rolling window of 1 to 5 years, you can extract changes in the style exposures of a manager.\n",
    221     "\n",
    222     "We'll look at Rolling Windows in the next lab session.\n",
    223     "\n",
    224     "As an exercise to the student, download a set of returns from Yahoo Finance, and try and measure the style drift in your favorite fund manager. Use reliable Value and Growth ETFs such as \"SPYG\" and \"SPYV\" along with a SmallCap ETF such as \"SLY\" and LargeCap ETF such as \"OEF\".\n",
    225     "\n",
    226     "Alternately, the Fama-French research factors and use the Top and Bottom portfolios by Value (HML) and Size (SMB) to categorize mutual funds into categories. This is very similar to the \"Style Box\" methodology employed by Morningstar and displayed on their website. Compare your results with their results to see if they agree!"
    227    ]
    228   },
    229   {
    230    "cell_type": "markdown",
    231    "metadata": {},
    232    "source": [
    233     "# Warning: Potential Misuse of Style Analysis\n",
    234     "\n",
    235     "Style Analysis works best when the explanatory indices are in fact a good specification of what is happening. For instance, it usually gives you very useful and revealing insight if you use a stock market index (such as SPY) and other broad indices, ETFs or mutual funds (such as a Value Fund, a Growth Fund, an International Fund, a Bond Fund etc).\n",
    236     "\n",
    237     "Part of the skill in extracting meaningful results is to pick the right set of explanatory variables.\n",
    238     "\n",
    239     "However, a part of the challenge with Style Analysis is that it will _always_ return a portfolio. Although it is possible to develop a figure of merit of fit quality similar to an $R^2$, it will still always give you an answer, however unreasonable it might be, and it's not always obvious how much one can rely on the result.\n",
    240     "\n",
    241     "For instance, we can try and extract the major industries that Buffer invested in since 2000 as follows:"
    242    ]
    243   },
    244   {
    245    "cell_type": "code",
    246    "execution_count": 8,
    247    "metadata": {},
    248    "outputs": [],
    249    "source": [
    250     "brka_m = pd.read_csv(\"brka_m.csv\", index_col=0, parse_dates=True).to_period('M')"
    251    ]
    252   },
    253   {
    254    "cell_type": "code",
    255    "execution_count": 9,
    256    "metadata": {},
    257    "outputs": [
    258     {
    259      "data": {
    260       "text/plain": [
    261        "Food     41.35\n",
    262        "Fin      17.61\n",
    263        "Meals    12.11\n",
    264        "Other    11.03\n",
    265        "Util      7.19\n",
    266        "Clths     5.99\n",
    267        "dtype: float64"
    268       ]
    269      },
    270      "execution_count": 9,
    271      "metadata": {},
    272      "output_type": "execute_result"
    273     }
    274    ],
    275    "source": [
    276     "mgr_r_b = brka_m[\"2000\":][\"BRKA\"]\n",
    277     "weights_b = erk.style_analysis(mgr_r_b, ind)\n",
    278     "weights_b.sort_values(ascending=False).head(6).round(4)*100"
    279    ]
    280   },
    281   {
    282    "cell_type": "markdown",
    283    "metadata": {},
    284    "source": [
    285     "If we want to look at the last decade (2009-2018):"
    286    ]
    287   },
    288   {
    289    "cell_type": "code",
    290    "execution_count": 10,
    291    "metadata": {},
    292    "outputs": [
    293     {
    294      "data": {
    295       "text/plain": [
    296        "Other    43.64\n",
    297        "Food     28.33\n",
    298        "Hlth     22.72\n",
    299        "Rtail     5.25\n",
    300        "Meals     0.07\n",
    301        "Books     0.00\n",
    302        "dtype: float64"
    303       ]
    304      },
    305      "execution_count": 10,
    306      "metadata": {},
    307      "output_type": "execute_result"
    308     }
    309    ],
    310    "source": [
    311     "brk2009 = brka_m[\"2009\":][\"BRKA\"]\n",
    312     "ind2009 = ind[\"2009\":]\n",
    313     "erk.style_analysis(brk2009, ind2009).sort_values(ascending=False).head(6).round(4)*100"
    314    ]
    315   },
    316   {
    317    "cell_type": "markdown",
    318    "metadata": {},
    319    "source": [
    320     "Should you believe the analysis? Probably not. However, when the specification is in fact accurate (as we saw in the articially generated series) the results can be very revealing"
    321    ]
    322   },
    323   {
    324    "cell_type": "code",
    325    "execution_count": null,
    326    "metadata": {},
    327    "outputs": [],
    328    "source": []
    329   }
    330  ],
    331  "metadata": {
    332   "kernelspec": {
    333    "display_name": "Python 3",
    334    "language": "python",
    335    "name": "python3"
    336   },
    337   "language_info": {
    338    "codemirror_mode": {
    339     "name": "ipython",
    340     "version": 3
    341    },
    342    "file_extension": ".py",
    343    "mimetype": "text/x-python",
    344    "name": "python",
    345    "nbconvert_exporter": "python",
    346    "pygments_lexer": "ipython3",
    347    "version": "3.8.8"
    348   }
    349  },
    350  "nbformat": 4,
    351  "nbformat_minor": 2
    352 }