Automated monitoring of the current weights of a portfolio


In [1]:
import matplotlib.pyplot as plt, numpy as np, pandas as pd
plt.style.use('bmh')
from matplotlib import rcParams
rcParams['font.family'] = 'Verdana'

Let's suppose that 3 months ago we built our portfolio with this macro asset allocation:
35% equity - 50% bonds - 15% precious metals

In order to reach this allocation we bought 22 ETFs/ETC listed on Italian Stock Exchange.

Let's suppose that after 2 months stock prices have fallen and precious metals prices have risen, mantaining the value of portfolio close to the initial capital of 100k, but with different weights. Moreover the relative weights of the asset within each macro asset have changed (for example the weight of gold is not anymore the same within the precious metals class, or the weight of equity emerging markets has changed compared to the initial weight).

We want to know which are the current weights of our portfolio.

Let's say that for each day we have an excel file named 'day'.xlsx where are reported the ETF tickers in our portfolio with the corresponding closing market value of the day.

Let's verify the new weights at the end of the chosen day:

In [2]:
# input the day we want to check out
day = input('Weights at the end of (dd-mm-yyyy):')
Weights at the end of (dd-mm-yyyy):10-02-2020
In [3]:
df = pd.read_excel( day + '.xlsx')
In [4]:
print('Portfolio at %s' % day)
Portfolio at 10-02-2020
In [5]:
df
Out[5]:
Ticker Value
0 AEEM 680
1 ALAT 1305
2 EPRA 1350
3 NRAM 12240
4 CSBGU7 4310
5 CSPXJ 2860
6 XCS2 3180
7 XDER 3025
8 XJSE 3560
9 CINA 1510
10 ITPS 3070
11 SAFRI 830
12 EM57 7610
13 LCJP 2475
14 MEUD 3515
15 RUS 730
16 JNKE 6055
17 CBEU5 6085
18 CBUS5 5180
19 EMLC 10280
20 PHAG 2510
21 PHPD 6020
22 SGBS 11795
23 CASH 475

We have 19 ETFs in our portfolio that replicate indexes of developed and emerging markets for stocks and bonds (in this notebook we don't group bond ETFs by government and corporate types), 3 ETC for precious metals, and a small amount of residual cash reported in the last row of the DataFrame.

In [6]:
# ETFs equity developed countries
equity_dev = ['NRAM','MEUD','LCJP','EPRA','XDER','CSPXJ']
# ETFs equity emerging countries
equity_eme = ['SAFRI', 'RUS', 'AEEM', 'ALAT', 'CINA']

# ETFs bonds developed countries
bond_dev = ['CSBGU7', 'CBUS5', 'ITPS', 'EM57', 'JNKE', 'CBEU5', 'XJSE', 'XCS2']
# ETFs bonds emerging countries
bond_eme = ['EMLC']

# ETC silver, palladium, gold
precious_metals = ['PHAG','PHPD','SGBS']

# total equity
equity = equity_dev + equity_eme
# total bond
bond = bond_dev + bond_eme
In [7]:
# the function the finds out the current weights of portfolio
def find_weight(compartment):
    weight = df[df['Ticker'].isin(compartment)]['Value'].sum(axis = 0) / df['Value'].sum(axis = 0)
    return round(weight,4)
In [8]:
# Let's see the total current asset allocation
# The small white area is the residual cash
weights = []
print('Asset allocation:\n')
for comp in (equity, bond, precious_metals):
    weights.append(find_weight(comp))
plt.figure(figsize = (8,6))
plt.pie(weights, labels = ['Equity', 'Bonds', 'Precious Metals'], autopct='%1.1f%%', textprops = {'fontsize' : 14});
Asset allocation:

In [9]:
# Let's draw pie charts to represent absolute weights and relative weights for each macro asset 
# (equity, bonds, precious metals)
def chart(macro_asset : str, comp1 : list, comp2: list, labels : list):
    ''' Args:
            macro_asset: equity, bonds or metals.
            comp1 : subset of tickers of the macro_asset
            comp2 : complementary subset of the same macro_asset 
    '''
    fig, ax = plt.subplots(1,2, figsize = (14,5))
    fig.suptitle(macro_asset, fontsize = 26, color = 'tan', y = 1.1)
    ax[0].pie([find_weight(comp1), find_weight(comp2)], labels = labels, autopct='%1.1f%%',textprops = {'fontsize' : 13});
    ax[1].pie([find_weight(comp1) / (find_weight(comp1) + find_weight(comp2)) \
               , 1 - find_weight(comp1) / (find_weight(comp1) + find_weight(comp2))]\
              , labels = labels, autopct='%1.1f%%', textprops = {'fontsize' : 13});
    ax[0].set_title('Absolute weights')
    ax[1].set_title('Relative weights');
In [10]:
macro = 'Equity'
labels = [macro + i for i in [' developed', ' emerging']]
chart(macro, equity_dev, equity_eme, labels)
In [11]:
macro = 'Bonds'
labels = [macro + i for i in [' developed', ' emerging']]
chart(macro, bond_dev, bond_eme, labels)
In [12]:
labels = ['Gold', 'Silver + Palladium']
chart('Precious metals', ['SGBS'], set(precious_metals) - set(['SGBS']), labels);