# importing libraries
import matplotlib.pyplot as plt
import plotly.graph_objs as go
import plotly.offline as py
import FutureAnalyser as fa
import cufflinks as cf
import seaborn as sns
import pandas as pd
import numpy as np
import quandl
import plotly
import time
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
from IPython.display import Markdown, display
from matplotlib.ticker import FuncFormatter
from pandas.core.base import PandasObject
from datetime import datetime
# Setting pandas dataframe display options
pd.set_option("display.max_rows", 20)
pd.set_option('display.width', 800)
pd.set_option('max_colwidth', 800)
pd.options.display.float_format = '{:,.2f}'.format
# Set plotly offline
init_notebook_mode(connected=True)
# Set matplotlib style
plt.style.use('seaborn')
# Set cufflinks offline
cf.go_offline()
# Defining today's Date
from datetime import date
today = date.today()
def compute_portfolio(quotes, weights, Nomes):
# Anos do Portfolio
Years = quotes.index.year.unique()
# Dicionário com Dataframes anuais das cotações dos quotes
Years_dict = {}
k = 0
for Year in Years:
# Dynamically create key
key = Year
# Calculate value
value = quotes.loc[str(Year)]
# Insert in dictionary
Years_dict[key] = value
# Counter
k += 1
# Dicionário com Dataframes anuais das cotações dos quotes
Quotes_dict = {}
Portfolio_dict = {}
k = 0
for Year in Years:
n = 0
#Setting Portfolio to be a Global Variable
global Portfolio
# Dynamically create key
key = Year
# Calculate value
if (Year-1) in Years:
value = Years_dict[Year].append(Years_dict[Year-1].iloc[[-1]]).sort_index()
else:
value = Years_dict[Year].append(Years_dict[Year].iloc[[-1]]).sort_index()
# Set beginning value to 100
value = (value / value.iloc[0]) * 100
#
for column in value.columns:
value[column] = value[column] * weights[n]
n +=1
# Get Returns
Returns = value.pct_change()
# Calculating Portfolio Value
value['Portfolio'] = value.sum(axis=1)
# Creating Weights_EOP empty DataFrame
Weights_EOP = pd.DataFrame()
# Calculating End Of Period weights
for Name in Nomes:
Weights_EOP[Name] = value[Name] / value['Portfolio']
# Calculating Beginning Of Period weights
Weights_BOP = Weights_EOP.shift(periods=1)
# Calculatins Portfolio Value
Portfolio = pd.DataFrame(Weights_BOP.multiply(Returns).sum(axis=1))
Portfolio.columns=['Simple']
# Transformar os simple returns em log returns
Portfolio['Log'] = np.log(Portfolio['Simple'] + 1)
# Cumsum() dos log returns para obter o preço do Portfolio
Portfolio['Price'] = 100*np.exp(np.nan_to_num(Portfolio['Log'].cumsum()))
Portfolio['Price'] = Portfolio['Price']
# Insert in dictionaries
Quotes_dict[key] = value
Portfolio_dict[key] = Portfolio
# Counter
k += 1
# Making an empty Dataframe for Portfolio data
Portfolio = pd.DataFrame()
for Year in Years:
Portfolio = pd.concat([Portfolio, Portfolio_dict[Year]['Log']])
# Delete repeated index values in Portfolio
Portfolio.drop_duplicates(keep='last')
# Naming the column of log returns 'Log'
Portfolio.columns= ['Log']
# Cumsum() dos log returns para obter o preço do Portfolio
Portfolio['Price'] = 100*np.exp(np.nan_to_num(Portfolio['Log'].cumsum()))
# Round Portfolio to 2 decimals and eliminate returns
Portfolio = pd.DataFrame(round(Portfolio['Price'], 2))
# Naming the column of Portfolio as 'Portfolio'
Portfolio.columns= ['Portfolio']
# Delete repeated days
Portfolio = Portfolio.loc[~Portfolio.index.duplicated(keep='first')]
return Portfolio
# Downloading funds and creating quotes and returns dataframes
# End = '2017-08-20' # Só activas se quiseres que acabe num dia especifíco
ISINs = ['DE000A0X7541', 'IE00BGCZ0933', 'IQQ0', 'IWDA']
Nomes = ['Acatis' , 'VG_GB', 'IQQ0', 'IWDA']
fundos = pd.read_csv('P:/GDrive/_GitHub/Backtester/Data/Cotacoes_diarias_all.csv', index_col = 'Date', parse_dates = True)[ISINs]
fundos.columns = Nomes
fundos = fundos.dropna()
fundos = fa.normalize(fundos)
Begin = fundos.head(1).index
Begin = str(Begin.strftime('%Y-%m-%d'))[8:18]
Dica: A interactividade dos gráficos da plotly permite:
. Zoom (mantenham o clique e arrastem o cursor em simultâneo, em cima do gráfico);
. Tem uma lista de opções que aparece se forem com o cursor ao canto superior direito;
. Façam duplo clique no gráfico ou seleccionem a opção Autoscale/Reset Axes para voltar ao normal;
. Alterem a opção de 'Compare data on hoover' para 'Show closest data on hoover' se vos for mais conveniente;
. Se clicarem num nome na legenda esse fundo desaparece (clicando de novo ele volta a apetecer).
# Making Color Palette
Palette = ['rgb(255, 153, 51)', # 1 - orange
'royalblue', # 2 - Royalblue
'#708090', # 3 - Grey
'rgb(128, 0, 128)', # 4 - Indigo
'rgb(219, 64, 82)', # 5 - Red
'rgb(0, 128, 128)', # 6 - Teal
'#191970', # 7 - Navy
'rgb(128, 128, 0)', # 8 - Olive
'#00BFFF', # 9 - Water Blue
'rgb(128, 177, 211)'] # 10 -
fundos.iplot(title='Performance dos fundos desde ' + Begin, yTitle='Valor de cada €100 investidos', color=Palette, dimensions=fa.dimensions)
Portfolios = compute_portfolio(fundos, [0, 0.25, 0.375, 0.375], Nomes=Nomes)
Portfolios.columns = ['ETFs_M']
Portfolios['Acatis'] = compute_portfolio(fundos, [1, 0, 0, 0], Nomes=Nomes)
fa.print_title('Valores finais dos Portfolios tendo começado em ' + Begin + ' com 100 euros')
Portfolios.tail(1)
Valores finais dos Portfolios tendo começado em 2015-03-10 com 100 euros
ETFs_M | Acatis | |
---|---|---|
2020-04-29 | 129.77 | 122.05 |
Portfolios.iplot(title='Performance dos portfolios desde ' + Begin, yTitle='Valor de cada €100 investidos', color=fa.colors, dimensions=fa.dimensions, kind='spread')
ratio = (Portfolios['Acatis'] / Portfolios['ETFs_M']) - 1
positive = pd.DataFrame(ratio[ratio >= 0]) * 100
negative = pd.DataFrame(ratio[ratio <= 0]) * 100
def merge_time_series(df_1, df_2, how='left'):
df = df_1.merge(df_2, how=how, left_index=True, right_index=True)
return df
ratio_2_colors = merge_time_series(positive, negative, how='outer')
ratio_2_colors.iplot(dimensions=(990, 500))
import plotly.graph_objects as go
x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
fig = go.Figure()
fig.add_trace(go.Scatter(
x=ratio_2_colors.index,
y=ratio_2_colors['0_x'] ,
name = '<b>No</b> Gaps', # Style name/legend entry with html tags
# connectgaps=True # override default to connect the gaps
))
fig.add_trace(go.Scatter(
x=ratio_2_colors.index,
y=ratio_2_colors['0_y'],
name='Gaps',
))
fig.show()
fig.add_trace(go.Scatter(
x=ratio_2_colors['0_x'],
y=ratio_2_colors['0_y'],
name = '<b>No</b> Gaps', # Style name/legend entry with html tags
connectgaps=True # override default to connect the gaps
))
ratio_2_colors
0_x | 0_y | |
---|---|---|
2015-03-10 | 0.00 | 0.00 |
2015-03-11 | nan | -0.40 |
2015-03-12 | nan | -0.63 |
2015-03-13 | nan | -0.79 |
2015-03-14 | nan | -0.79 |
2015-03-15 | nan | -0.79 |
2015-03-16 | nan | -0.71 |
2015-03-17 | nan | -0.98 |
2015-03-18 | nan | -0.65 |
2015-03-19 | nan | -1.35 |
... | ... | ... |
2020-04-20 | nan | -5.07 |
2020-04-21 | nan | -5.11 |
2020-04-22 | nan | -5.24 |
2020-04-23 | nan | -5.48 |
2020-04-24 | nan | -4.86 |
2020-04-25 | nan | -4.86 |
2020-04-26 | nan | -4.86 |
2020-04-27 | nan | -5.39 |
2020-04-28 | nan | -5.95 |
2020-04-29 | nan | -5.95 |
1878 rows × 2 columns
data = [
[1, 13, 10, 15],
[2, 13, 15, 20],
[3, 17, 15, 20]
]
df = pd.DataFrame(
data,
columns=['x', 'y', 'lower_limit', 'upper_limit']
)
trace = go.Scatter(
x=df['x'],
y=df['y'],
mode='markers',
marker=dict(
size=42,
# I want the color to be green if
# lower_limit ≤ y ≤ upper_limit
# else red
color=(
(df.lower_limit < df.y) &
(df.y < df.upper_limit)
).astype('int'),
colorscale=[[0, 'red'], [1, 'green']]
)
)
py.iplot([trace])
DD = fa.compute_drawdowns(Portfolios)
DD = DD /100
layout = go.Layout(
title='Drawdown dos portfolios desde ' + Begin,
plot_bgcolor='#f5f5f5',
paper_bgcolor='#f5f5f5',
width=990,
height=500,
xaxis=dict(
title='',
showgrid=True,
titlefont=dict(size=12),
),
yaxis=dict(
title='',
showgrid=True,
zeroline=True, # Adicionar ou não a zero line
tickformat=".1%" # tickformat=".2%" se quiseres mais casas decimais
))
trace0 = go.Scatter(
x = DD.index,
y = DD.iloc[:, 0],
name = Portfolios.columns[0],
line = dict(
color = 'royalblue',
width = 1.3)
)
trace1 = go.Scatter(
x = DD.index,
y = DD.iloc[:, 1],
name = Portfolios.columns[1],
line = dict(
color = 'dimgrey',
width = 1.3)
)
data = [trace0, trace1]
fig = go.Figure(data=data, layout=layout)
py.iplot(fig)
fa.print_title('Drawdown actual (' + str(DD.iloc[-1].name)[0:10] + ')')
DD = fa.compute_drawdowns(Portfolios)
DD = DD /100
round(DD.tail(1), 5).applymap(lambda x: "{0:.2f}%".format(x*100))
Drawdown actual (2020-04-29)
ETFs_M | Acatis | |
---|---|---|
2020-04-29 | -10.98% | -10.66% |
layout = go.Layout(
title='Diferencial de performance entre os portfolios desde ' + Begin,
plot_bgcolor='#f5f5f5',
paper_bgcolor='#f5f5f5',
width=990,
height=500,
xaxis=dict(
title='<b>Nota:</b> Subida a favor de ' + Portfolios.columns[0] + ', descida a favor de ' + Portfolios.columns[1],
showgrid=True,
titlefont=dict(size=12),
),
yaxis=dict(
title='',
showgrid=True,
zeroline=True, # Adicionar ou não a zero line
tickformat=".1%" # tickformat=".2%" se quiseres mais casas decimais
))
trace0 = go.Scatter(
x = fundos.index,
y = (round(((Portfolios.iloc[:, 0]/Portfolios.iloc[:, 1])- 1), 5)),
name = 'Portfolio',
line = dict(
color = 'darkorchid',
width = 1.3)
)
data = [trace0]
fig = go.Figure(data=data, layout=layout)
py.iplot(fig)
fa.print_title('Performance da carteira ETF Moderada desde ' + Begin)
fa.compute_ms_performance_table(Portfolios[['ETFs_M']])
Performance da carteira ETF Moderada desde 2015-03-10
--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-26-1bec636dcd6c> in <module> 1 fa.print_title('Performance da carteira ETF Moderada desde ' + Begin) ----> 2 fa.compute_ms_performance_table(Portfolios[['ETFs_M']]) P:\GDrive\_GitHub\Articles_and_studies\FutureAnalyser.py in compute_ms_performance_table(DataFrame, freq) 820 elif nr_of_days >= 365*5 and nr_of_days < 365*10: 821 df0 = compute_performance_table(DataFrame) --> 822 df_ytd = compute_performance_table(DataFrame, years='ytd') 823 df1 = compute_performance_table(filter_by_date(DataFrame, years=1), freq=freq) 824 df3 = compute_performance_table(filter_by_date(DataFrame, years=3), freq=freq) P:\GDrive\_GitHub\Articles_and_studies\FutureAnalyser.py in compute_performance_table(dataframe, years, freq, investment_value) 175 if years == 'ytd': 176 df = pd.DataFrame([compute_ytd_return(dataframe), compute_cagr(dataframe, years), compute_ytd_StdDev(dataframe), --> 177 compute_ytd_sharpe(dataframe), compute_ytd_max_DD(dataframe), compute_ytd_mar(dataframe)]) 178 df.index = ['Return', 'CAGR', 'StdDev', 'Sharpe', 'Max DD', 'MAR'] 179 NameError: name 'compute_ytd_max_DD' is not defined