# Preparazione dei dati

0.1 Importazione serie storiche

Il codice sotto (per visualizzare il codice cliccare sul tasto code) mostrato crea una lista di ticker (i.e. simbolo di un titolo) in tickerList e assegna a ciascuno di essi un peso (weight). Successivamente, utilizza la funzione lapply per scaricare i dati storici delle azioni corrispondenti a ciascun ticker dal sito Yahoo Finance, utilizzando la funzione getSymbols. I dati vengono scaricati per il periodo compreso tra il 15 dicembre 2017 e il 16 dicembre 2022. Una volta scaricati i dati, essi vengono memorizzati in un oggetto stockData. In questo modo, potrete avere accesso ai dati storici di diversi titoli.

tickerList = c("SPG", # REITS
               "OHI",
               "CCOM.TO",  # Commodities
               "DBC",
               "FCX",
               "KSM-F6.TA",
               "0P0001MN8G.F",  # CAT BOND
               "CDZ.TO",   # dividend
               "NOBL",
               "NSRGY",
               "CNI",
               "WFAFY",
               "UU.L",
               "KO",
               "NVS",
               "NVDA", # nvidia no dividendi
               # "SHY",  # short term bond -- in verità sono etf che riproducono l'andamento
               # "VGSH",
               "SPTS",
               "IBGS.AS",
               "6C=F",  # cash -- ho messo un future sui dollari canadesi per rappresentare la liquidità
               # "XT2D.L",  # swap  -- non sapevo cosa mettere
               "XGIU.MI") # Inflation linked
# weightOLD = c(.12,.13,.07,.11,.15,.23,.19)
weight = c(
  .08,
  .06,
  .046, # comodities
  .009,
  .01,
  .057,
  .07, # cat bond
  .02, # div
  .06, 
  .02,
  .01,
  .017,
  .005,
  .005,
  .05,
  .023,
  # .07,
  # .07,
  .05,
  .128,
  .15,
  # .00,
  .13
)
sum(weight)
## [1] 1
stockData = lapply(1:length(tickerList),
                   function(i)
                     getSymbols(
                       Symbols = tickerList[i],
                       src = "yahoo",
                       from = as.Date("2018-09-30"),
                       to = as.Date("2023-09-29"),
                       auto.assign = F
                     ))

tickerList[tickerList == "KSM-F6.TA"] = "KSM.F6.TA"
tickerList[tickerList == "6C=F"] = "X6C"

Il codice sotto mostrato unisce i dati delle diverse azioni scaricate in precedenza in un unico oggetto nominalPortfolio utilizzando la funzione merge. In seguito, elimina le osservazioni mancanti dall’oggetto utilizzando la funzione na.omit. Infine, il codice esegue un ciclo per ciascun ticker presente nella lista tickerList, seleziona le colonne del nominalPortfolio che corrispondono al ticker in questione e che non sono relative al volume, e divide queste colonne per il valore del primo giorno di osservazione per quel ticker, ottenendo così gli indici a base fissa equivalente al primo giorno della serie storica. In questo modo, i dati del nominalPortfolio vengono normalizzati in base al valore del primo giorno di osservazione per ciascun ticker.

nominalPortfolio = do.call(merge,stockData) %>%
  na.omit 
nominalPortfolio$X0P0001MN8G.F.Volume = 1

for(i in 1:length(tickerList))
{
  # print(i)
  columnSelect = (!names(nominalPortfolio) %like% "Volume") & names(nominalPortfolio) %like% tickerList[i]
  nominalPortfolio[,columnSelect] = nominalPortfolio[,columnSelect] / rep(coredata(nominalPortfolio[1,columnSelect])[1],5) 
}

as_tibble(nominalPortfolio)

Il grafico mostra il risultato di una serie di operazioni effettuate sui dati del portafoglio in una matrice chiamata portfolio. In particolare, questo codice utilizza un ciclo for per iterare attraverso ogni ticker nella lista tickerList. Per ciascun ticker, il codice utilizza una selezione di colonne basata sulla condizione che i nomi delle colonne non contengano Volume e contengano il ticker corrente. Una volta selezionate le colonne corrette, il codice moltiplica i valori delle colonne selezionate con i pesi corrispondenti del titolo, che sono contenuti nel vettore weight[i].

portfolio = nominalPortfolio

for(i in 1:length(tickerList))
{
  columnSelect = (!names(portfolio) %like% "Volume") & names(portfolio) %like% tickerList[i]
  portfolio[,columnSelect] = coredata(nominalPortfolio[,columnSelect]) * weight[i] 
}

as_tibble(portfolio)

0.2 Creazione portafoglio

Il codice sotto mostrato crea una matrice myPortfolio vuota e assegna i nomi delle colonne utilizzando la lista columnNames. Successivamente, esegue un ciclo per ciascuna colonna e seleziona le colonne del portfolio che corrispondono al nome della colonna in questione. In seguito, utilizza la funzione sapply per calcolare la somma di tutte le colonne selezionate per ogni riga della matrice myPortfolio. Una volta completata la matrice, viene assegnato a myPortfolio il formato xts (time series) utilizzando l’indice del portfolio come data di riferimento. In questo modo, avrete a disposizione i dati del vostro portafoglio in formato xts e potrete utilizzarli per analizzare le performance del portafoglio o per fare previsioni sui futuri andamenti dei mercati.

columnNames = c("Open", "High", "Low", "Close", "Volume", "Adjusted")
myPortfolio = matrix(NA, nrow(portfolio),ncol = length(columnNames))

for(i in 1:length(columnNames))
{
  columnSelect = names(portfolio) %like% columnNames[i]
  myPortfolio[,i] = sapply(1:nrow(portfolio), function(r) sum(coredata(portfolio[r,columnSelect])))  
}

colnames(myPortfolio) = paste("Ragionevole", columnNames, sep = ".")
myPortfolio = xts(myPortfolio, order.by = index(portfolio))

as_tibble(myPortfolio)

1 Decomposizione serie storica

Il seguente pezzo di codice è utilizzato per analizzare l’andamento mensile del portafoglio e “decomporre” la serie storica in tre componenti distinte: un andamento stagionale, un andamento tendenziale e una componente casuale.

La funzione decompose() utilizzata nel codice è una funzione di base di R che utilizza un algoritmo di decomposizione chiamato “stima e filtraggio”. Questo algoritmo analizza la serie storica e separa i dati in queste tre componenti.

La prima riga di codice utilizza la funzione to.monthly() per convertire i dati del portafoglio da giornalieri a mensili, in modo da avere una visione più generale dell’andamento del portafoglio. La seconda riga utilizza decompose() per effettuare la decomposizione e salva il risultato nella variabile pfDecomposto.

In sintesi, questo pezzo di codice ci permette di analizzare l’andamento mensile del portafoglio e ci fornisce una comprensione più profonda dei fattori che influenzano l’andamento del portafoglio, sia a livello stagionale che tendenziale. Ci aiuta ad identificare possibili opportunità e rischi, per fare previsioni più informate.

# weeklyPortfolio = Cl(to.weekly(myPortfolio))
# pfDecomposto = decompose(as.ts(weeklyPortfolio, start=c(2022,9,29)))
# plot(pfDecomposto)

2 Ottimizzazione

In questo capitolo, ci concentreremo sull’ottimizzazione del portafoglio. Il nostro obiettivo è trovare il giusto equilibrio tra il rischio misurato dal VaR e il rendimento del portafoglio. Per raggiungere questo obiettivo, ci concentreremo sull’assegnazione del peso appropriato per ogni singolo titolo del portafoglio.

È importante notare che basare la valutazione di un titolo solo sul rendimento medio degli ultimi anni e sulla sua varianza può essere restrittivo. Questo metodo non tiene conto di molti altri fattori che influiscono sull’andamento di un titolo. Pertanto, abbiamo stabilito dei vincoli sull’ottimizzazione per garantire che i pesi scelti vengano migliorati senza essere stravolti.

Il codice calcola i rendimenti per ogni titolo, trasforma i rendimenti in contributi annuali e elimina eventuali valori mancanti. Quindi, calcola la media dei rendimenti per ogni titolo, la matrice di covarianza per i rendimenti trimestrali dei titoli, il Value at Risk per i rendimenti trimestrali del portafoglio e il rischio del portafoglio utilizzando la matrice di covarianza e pesi del portafoglio. Infine, calcola il rapporto di Sharpe, una metrica comunemente utilizzata per valutare la performance del portafoglio rispetto al rischio.

nominalPortfolioAdj = nominalPortfolio[,names(nominalPortfolio) %like% "Adjusted"] %>%
  CalculateReturns() %>% 
  to.yearly.contributions() %>% 
  na.omit()

nominalPortfolioAdj = nominalPortfolioAdj[,names(nominalPortfolioAdj) != "Portfolio Return"]

mean_ret <- colMeans(nominalPortfolioAdj)

cov_mat = nominalPortfolio[,names(nominalPortfolio) %like% "Adjusted"] %>%
  CalculateReturns() %>% 
  to.quarterly.contributions() %>% 
  na.omit() %>% 
  cov()

# solo quando i volumi non sono degeneri

# return3mesi = nominalPortfolio %>%
#   CalculateReturns() %>% 
#   to.period.contributions("quarters") %>% 
#   na.omit()
# 
# var3m = VaR(R = return3mesi[,names(return3mesi) %like% "Adjusted"],
#             method = "historical",
#       portfolio_method = "component",
#       weights = weight)

# port_risk = var3m$hVaR

cov_mat = cov_mat[rownames(cov_mat) != "Portfolio Return",
                  colnames(cov_mat) != "Portfolio Return"]

port_returns = sum(mean_ret * weight)

port_risk <- sqrt(t(weight) %*% (cov_mat %*% weight))

sharpe_ratio <- port_returns/port_risk

tibble("Return" = port_returns,
       "Risk" = port_risk,
       # "VaR a 3 mesi" = var3m$hVaR,
       "Sharpe ratio" = sharpe_ratio)

Il seguente pezzo di codice è dedicato alla ricerca dei valori. Vengono generati 5000 portafogli diversi, con diversi pesi dei titoli che compongono il portafoglio. Ogni portafoglio viene poi valutato con le metriche precedentemente descritte.

Infine, nei successivi pezzi di codice vengono mostrati dei grafici che rappresentano il lavoro dell’algoritmo appena descritto. L’ultimo grafico è il più importante, nella quale si può vedere la distribuzione della frontiera efficiente, ovvero l’insieme dei valori con miglior sharpe ratio. Per scegliere i pesi più adatti alle proprie necessità ci sono due tecniche. La prima consiste nel fissare il VaR e cercare il rendimento più alto. La seconda, invece, è l’opposto. Fissato il rendimento desiderato, si minimizza il VaR.

set.seed(1)
num_port <- 5000

# Creating a matrix to store the weights

all_wts <- matrix(nrow = num_port,
                  ncol = length(tickerList))

# Creating an empty vector to store
# Portfolio returns

port_returns <- vector('numeric', length = num_port)

# Creating an empty vector to store
# Portfolio Standard deviation

port_risk <- vector('numeric', length = num_port)

# Creating an empty vector to store
# Portfolio Sharpe Ratio

sharpe_ratio <- vector('numeric', length = num_port)

for (i in seq_along(port_returns)) {
  precisione = 0.9
  wts = sapply(1:length(weight), function(i) runif(1,precisione * weight[i], (2 - precisione) * weight[i]))
  # wts = runif(length(tickerList))
  wts <- wts/sum(wts)
  
  # Storing weight in the matrix
  all_wts[i,] <- wts
  
  # Portfolio returns
  
  port_ret <- sum(wts * mean_ret)
  # port_ret <- ((port_ret + 1)^252) - 1
  
  # Storing Portfolio Returns values
  port_returns[i] <- port_ret
  
  
  # Creating and storing portfolio risk
  port_sd <- sqrt(t(wts) %*% (cov_mat  %*% wts))

  # Più preciso ma ci mette troppo  
  # port_sd = VaR(
  #   R = return3mesi[, names(return3mesi) %like% "Adjusted"],
  #   method = "historical",
  #   portfolio_method = "component",
  #   weights = wts
  # )$hVaR

  port_risk[i] <- port_sd
  
  
  # Creating and storing Portfolio Sharpe Ratios
  # Assuming 0% Risk free rate
  
  sr <- port_ret/port_sd
  sharpe_ratio[i] <- sr
  
}

Di seguito vengono mostrati i pesi assegnati dal portafoglio con sharpe ratio maggiore.

# Storing the values in the table
portfolio_values <- tibble(Return = port_returns,
                  Risk = port_risk,
                  SharpeRatio = sharpe_ratio)


# Converting matrix to a tibble and changing column names
all_wts <- all_wts %>%
  data.frame() %>%
  tibble
colnames(all_wts) <- tickerList

# Combing all the values together
portfolio_values <- tibble(cbind(all_wts, portfolio_values))
colnames(portfolio_values)[1:length(tickerList)] = tickerList

min_var <- portfolio_values[which.min(portfolio_values$Risk),]
max_sr <- portfolio_values[which.max(portfolio_values$SharpeRatio),]

weightOLD = weight
weight = max_sr[,1:length(tickerList)] %>% 
  as.numeric() %>% 
  round(4) 

# con l'arrotondamento potrebbe non fare 1 e lo calibro con il primo titolo, ciò non influenzerà significativamente sullo scostamento del portafoglio
weight[1] = weight[1] + 1 - sum(weight)

max_sr

I grafici di seguito riportati sono interattivi, posizionandosi sopra con il mouse si potranno osservare maggiori informazioni.

p <- min_var %>%
  gather(1:length(tickerList), key = Asset,
         value = Weights) %>%
  mutate(Asset = as.factor(Asset)) %>%
  ggplot(aes(x = fct_reorder(Asset,Weights), y = Weights, fill = Asset)) +
  geom_bar(stat = 'identity') +
  theme_minimal() +
  labs(x = 'Titoli', y = 'Pesi', title = "Pesi del portafoglio con VaR minimo") +
  scale_y_continuous(labels = scales::percent) +
  theme(legend.position = "none") +
  coord_flip()

ggplotly(p)
p <- max_sr %>%
  gather(tickerList[1]:tickerList[length(tickerList)], key = Asset,
         value = Weights) %>%
  mutate(Asset = as.factor(Asset)) %>%
  ggplot(aes(x = fct_reorder(Asset,Weights), y = Weights, fill = Asset)) +
  geom_bar(stat = 'identity') +
  theme_minimal() +
  labs(x = 'Titoli',
       y = 'Pesi',
       title = "Pesi del portafoglio tangente alla frontiera efficiente") +
  scale_y_continuous(labels = scales::percent) +
  theme(legend.position = "none") +
  coord_flip()


ggplotly(p)
p <- portfolio_values %>%
  ggplot(aes(x = Risk, y = Return, color = SharpeRatio)) +
  geom_point() +
  theme_classic() +
  scale_y_continuous(labels = scales::percent) +
  scale_x_continuous(labels = scales::percent) +
  labs(x = 'Rischio annuo',
       y = 'Rendimento annuo',
       title = "Ottimizzazione di portafoglio e frontiera efficiente") +
  geom_point(aes(x = Risk,
                 y = Return),
             data = min_var,
             color = 'violet') +
  geom_point(aes(x = Risk,
                 y = Return),
             data = max_sr,
             color = 'aquamarine')
ggplotly(p)
# Da esguire se si vuole rendimento più alto ma con diversificazione minore

# weightOLD = weight
# weight = portfolio_values[round(portfolio_values$SharpeRatio, 6) == 2.670734 & round(portfolio_values$Risk, 5) == 0.030190,1:length(tickerList)] %>% 
#   as.numeric() %>% 
#   round(4) 
# 
# # con l'arrotondamento potrebbe non fare 1 e lo calibro con il primo titolo, ciò non influenzerà significativamente sullo scostamento del portafoglio
# weight[1] = weight[1] + 1 - sum(weight)
# ricreo il portafoglio con i nuovi pesi
portfolio = nominalPortfolio

for(i in 1:length(tickerList))
{
  columnSelect = (!names(portfolio) %like% "Volume") & names(portfolio) %like% tickerList[i]
  portfolio[,columnSelect] = coredata(nominalPortfolio[,columnSelect]) * weight[i] 
}

columnNames = c("Open", "High", "Low", "Close", "Volume", "Adjusted")
myPortfolio = matrix(NA, nrow(portfolio),ncol = length(columnNames))

for(i in 1:length(columnNames))
{
  columnSelect = names(portfolio) %like% columnNames[i]
  myPortfolio[,i] = sapply(1:nrow(portfolio), function(r) sum(coredata(portfolio[r,columnSelect])))  
}

colnames(myPortfolio) = paste("Ragionevole", columnNames, sep = ".")
myPortfolio = xts(myPortfolio, order.by = index(portfolio))

3 VaR

returnTicker = xts()
for(i in 1:length(tickerList))
  returnTicker = cbind(returnTicker,dailyReturn(Cl(nominalPortfolio[,names(portfolio) %like% tickerList[i]])))
colnames(returnTicker) = tickerList

returnTickerIndici = returnTicker %>% 
  as.tibble() %>%
  summarise_all(sum) %>% 
  pivot_longer(1:length(tickerList), names_to = "Titoli", values_to = "Rendimento")  %>% 
  add_column(returnTicker %>%
               as.tibble() %>%
               summarise_all(sd) %>%
               pivot_longer(1:length(tickerList), names_to = "Titoli", values_to = "Varianza") %>% 
               dplyr::select(Varianza)
             ) %>% 
  mutate(Variazione = ifelse(round(Rendimento, 2) != 0,
                             Varianza/abs(Rendimento),
                             1)) 
## Warning: `as.tibble()` was deprecated in tibble 2.0.0.
## ℹ Please use `as_tibble()` instead.
## ℹ The signature and semantics have changed, see `?as_tibble`.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
returnTickerIndici %>% 
  ggplot(aes(Titoli, Variazione, fill = Varianza)) +
  geom_col() + 
  coord_flip() +
  scale_fill_gradient2(high = "mediumvioletred",
                       # mid = "mediumvioletred",
                       low = "mediumspringgreen",
                       midpoint = median(returnTickerIndici$Varianza))

returnTickerIndici %>% 
  ggplot(aes(y = Rendimento, x = Titoli, fill = Varianza)) +
  geom_col() + 
  coord_flip() +
  scale_fill_distiller(palette = "RdYlGn", direction = -1)

  # ylim(c(-0.08,0.12))
  
returnTicker %>% 
  as.tibble() %>% 
  pivot_longer(1:length(tickerList), names_to = "Titoli", values_to = "Rendimento") %>%
  ggplot(aes(y = Rendimento, x = Titoli)) +
  geom_boxplot() + 
  coord_flip() +
  ylim(c(-0.08,0.12))
## Warning: Removed 6 rows containing non-finite values (`stat_boxplot()`).

3.1 VaR storico

Il VaR è una misura del rischio che indica la perdita massima probabile che il portafoglio potrebbe subire con un determinato livello di confidenza. Nel caso specifico, il codice calcola il VaR utilizzando il metodo storico e un livello di confidenza del 95%.

Il codice inizia dividendo il portafoglio in trimestri e calcolando i rendimenti per ogni trimestre utilizzando la funzione CalculateReturns(). Quindi, utilizzando la funzione to.period.contributions() si trasformano i rendimenti in contributi trimestrali e si estraggono solo quelli che contengono “Adjusted” nel loro nome. Successivamente, con la funzione VaR() si calcola il VaR utilizzando i rendimenti trimestrali estratti, i pesi del portafoglio, il metodo storico e il metodo per il portafoglio “component”, il quale indica che il VaR è calcolato per ogni componente del portafoglio e poi sommato.

Infine, è importante notare che il VaR calcolato utilizzando il metodo storico si basa sui dati storici del portafoglio e potrebbe non essere un indicatore preciso del rischio futuro. Pertanto, sarebbe opportuno utilizzare anche altre metodologie per valutare il rischio del portafoglio, come ad esempio il Value at Risk condizionale o l’analisi di stress.

return3mesi = nominalPortfolio %>% 
  CalculateReturns %>% 
  to.period.contributions("quarters")


weight_max_sr = max_sr %>% 
      t() %>% 
      head(length(tickerList)) %>% 
      as.vector()

VaR(return3mesi[,names(return3mesi) %like% "Adjusted"],
    method = "historical",
    weights = weight_max_sr,
    portfolio_method = "marginal") %>% 
  pivot_longer(1:length(weight_max_sr)+1, names_to = "Titoli", values_to = "VaR") %>% 
  mutate(VaR = round(VaR *100, 2)) %>% 
  ggplot(aes(x = Titoli, y = VaR, fill = VaR)) +
  geom_col() +
  coord_flip() +
  scale_fill_distiller(palette = "RdYlGn", direction = -1) +
  theme(legend.position = "none")

VaR(return3mesi[,names(return3mesi) %like% "Adjusted"] %>% na.omit(),
    method = "historical",
    weights = weight_max_sr,
    portfolio_method = "component")
## $hVaR
##    hVaR 95% 
## -0.01108171 
## 
## $contribution
##           SPG.Adjusted           OHI.Adjusted       CCOM.TO.Adjusted 
##                    NaN                    NaN                    NaN 
##           DBC.Adjusted           FCX.Adjusted     KSM.F6.TA.Adjusted 
##                    NaN                    NaN                    NaN 
## X0P0001MN8G.F.Adjusted        CDZ.TO.Adjusted          NOBL.Adjusted 
##                    NaN                    NaN                    NaN 
##         NSRGY.Adjusted           CNI.Adjusted         WFAFY.Adjusted 
##                    NaN                    NaN                    NaN 
##          UU.L.Adjusted            KO.Adjusted           NVS.Adjusted 
##                    NaN                    NaN                    NaN 
##          NVDA.Adjusted          SPTS.Adjusted       IBGS.AS.Adjusted 
##                    NaN                    NaN                    NaN 
##         X6C.F.Adjusted       XGIU.MI.Adjusted 
##                    NaN                    NaN 
## 
## $pct_contrib_hVaR
##           SPG.Adjusted           OHI.Adjusted       CCOM.TO.Adjusted 
##                    NaN                    NaN                    NaN 
##           DBC.Adjusted           FCX.Adjusted     KSM.F6.TA.Adjusted 
##                    NaN                    NaN                    NaN 
## X0P0001MN8G.F.Adjusted        CDZ.TO.Adjusted          NOBL.Adjusted 
##                    NaN                    NaN                    NaN 
##         NSRGY.Adjusted           CNI.Adjusted         WFAFY.Adjusted 
##                    NaN                    NaN                    NaN 
##          UU.L.Adjusted            KO.Adjusted           NVS.Adjusted 
##                    NaN                    NaN                    NaN 
##          NVDA.Adjusted          SPTS.Adjusted       IBGS.AS.Adjusted 
##                    NaN                    NaN                    NaN 
##         X6C.F.Adjusted       XGIU.MI.Adjusted 
##                    NaN                    NaN

3.2 VaR grafico

Nel seguente grafico è rappresentato l’istogramma dei rendimenti trimestrali simulati da una distribuzione normale con media pari al rendimento medio del portafoglio e deviazione standard pari alla volatilità del portafoglio. In questo caso il VaR è calcolato con il metodo gaussiano.

media = sapply(1:nrow(return3mesi), function(i) sum(return3mesi[i,names(nominalPortfolio) %like% "Adjusted"] * weight)) %>% mean(na.rm = T)

varianza = sapply(1:nrow(return3mesi), function(i) sum(return3mesi[i,names(nominalPortfolio) %like% "Adjusted"] * weight)) %>% sd(na.rm = T)

set.seed(1)
df = data.frame(x = rnorm(1E6, media, varianza))
ggplot(df, aes(x, ..density..)) +
  geom_histogram(color = "violet",
                 fill = "orchid1",
                 alpha = .5) +
  geom_density(color = "aquamarine") +
  geom_vline(xintercept = quantile(df$x, probs = .05),
             color = "aquamarine2") +
  annotate('text',
           x = quantile(df$x, probs = .05),
           y = 0.01,
           color = "aquamarine4",
           label = paste("VaR = ",df$x %>% 
                           quantile(probs = .05) %>% 
                           round(4))) +
  theme_light()
## Warning: The dot-dot notation (`..density..`) was deprecated in ggplot2 3.4.0.
## ℹ Please use `after_stat(density)` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

3.3 Correlazione tra titoli

Un correlogramma è un tipo di grafico che mostra la relazione di correlazione tra diverse variabili. Nel codice specifico, il correlogramma mostra la relazione di correlazione tra i diversi titoli che compongono il portafoglio.

Il codice inizia calcolando la matrice di correlazione tra i rendimenti trimestrali dei titoli estratti tramite il comando cor() e si omettono i valori mancanti. Successivamente, i nomi delle colonne e delle righe vengono modificati in modo da rimuovere il suffisso “.Adjusted”. Infine, utilizzando la libreria corrplot e il metodo “number” si crea il correlogramma, con titolo “Correlogramma dei titoli che compongono il portafoglio”, utilizzando il metodo “ward.D2” per l’elaborazione dei cluster e impostando “diag” a F in modo che non venga mostrato la diagonale del correlogramma, che rappresenta la correlazione di un titolo con se stesso.

Come consulente finanziario, è importante notare che la correlazione tra i titoli che compongono il portafoglio può influire significativamente sulla performance del portafoglio e sulla sua diversificazione. Il correlogramma ci permette di visualizzare rapidamente quali titoli sono correlati tra loro e di prendere decisioni informate su quali titoli includere o escludere dal portafoglio.

correlazione = return3mesi[,names(return3mesi) %like% "Adjusted"] %>% 
  na.omit %>% 
  cor

colnames(correlazione) = stringr::str_remove(colnames(correlazione),".Adjusted")
rownames(correlazione) = stringr::str_remove(colnames(correlazione),".Adjusted")
  
# correlazione %>%   
#   corrplot::corrplot(method = "number",
#                      # title = "Correlogramma dei titoli che compongono il portafoglio",
#                      hclust.method = "ward.D2",
#                      diag = F,
#                      type = "upper")

correlazione %>% 
  reshape2::melt() %>% 
  ggplot(aes(x=Var1, y=Var2, fill=value)) + 
  geom_tile() +
  scale_fill_distiller(palette = "RdYlGn")

4 Grafici

4.1 Grafici interattivi

4.1.1 Grafico indicizzato

Il grafico che segue mostra i diversi titoli che compongono il vostro portafoglio, indicizzati in base al valore del primo giorno di osservazione della serie storica.

Il grafico è interattivo: posizionando il mouse sopra, sarà possibile visualizzare i valori degli indici per ciascun titolo, facilitando il confronto tra i diversi titoli e il loro andamento nel tempo. Questo vi permetterà di avere una panoramica dettagliata delle prestazioni del vostro portafoglio e di valutare se le vostre scelte di investimento sono state proficue.

grafico = highchart(type = "stock")
for(i in 1:length(tickerList))
  grafico = hc_add_series(grafico, 
                          Cl(nominalPortfolio[,names(portfolio) %like% tickerList[i]]),
                          name = tickerList[i])
grafico

4.1.2 Grafico indicizzato con pesi del portafoglio

Il grafico seguente, simile al precedente, mostra invece gli indici dei titoli e i relativi pesi con cui il vostro portafoglio è caratterizzato. Attraverso questo grafico, potrete comprendere meglio come le variazioni di un titolo influiscano sul vostro portafoglio. Potrete facilmente individuare quali titoli hanno un maggiore impatto sulle performance del portafoglio e valutare se i pesi assegnati alle diverse posizioni sono adeguati al vostro profilo di rischio e agli obiettivi di investimento. In questo modo, potrete prendere decisioni informate su come allocare il vostro portafoglio e ottimizzare le prestazioni.

grafico = highchart(type = "stock")
for(i in 1:length(tickerList))
  
  grafico = hc_add_series(grafico, 
                          Cl(portfolio[,names(portfolio) %like% tickerList[i]]),
                          name = tickerList[i]) 
grafico

4.2 Rendimento giornaliero del portafoglio

Il codice sotto mostrato restituisce il rendimento giornaliero del vostro portafoglio, calcolato utilizzando i dati del prezzo di chiusura delle posizioni che compongono il portafoglio. Successivamente, viene generato un grafico di performance che riassume le prestazioni del portafoglio nel tempo. In questo modo, potrete avere una panoramica chiara e dettagliata delle performance del vostro portafoglio e valutare se le vostre scelte di investimento sono state proficue. Questo vi permetterà di prendere decisioni informate e di adattare il vostro portafoglio alle condizioni di mercato in evoluzione.

returnMyPortfolio = dailyReturn(Cl(myPortfolio))
charts.PerformanceSummary(as.xts(returnMyPortfolio))

4.3 Performance portafoglio

Il codice sopra mostrato calcola il rendimento giornaliero per ciascun titolo che compone il vostro portafoglio, utilizzando i dati del prezzo di chiusura delle posizioni. I rendimenti vengono poi inseriti in un oggetto xts e i nomi delle colonne vengono impostati sulla lista dei ticker (i titoli che compongono il vostro portafoglio). Infine, viene generato un grafico di performance che riassume le prestazioni dei singoli titoli nel vostro portafoglio. In questo modo, potrete avere una panoramica dettagliata delle performance dei singoli titoli che compongono il vostro portafoglio e valutare l’impatto di ciascun titolo sulle prestazioni complessive del portafoglio. Questo vi permetterà di prendere decisioni informate su come allocare il vostro portafoglio e ottimizzare le prestazioni.

# returnTicker = xts()
# for(i in 1:length(tickerList))
#   returnTicker = cbind(returnTicker,dailyReturn(Cl(nominalPortfolio[,names(portfolio) %like% tickerList[i]])))
# colnames(returnTicker) = tickerList

charts.PerformanceSummary(returnTicker,main = "Performance portafoglio Ragionevole")

chartSeries(myPortfolio)

5 Previsione serie storica

5.1 Modello ARIMA

Il codice sotto mostrato utilizza la libreria forecast per prevedere il comportamento futuro del vostro portafoglio utilizzando un modello ARIMA. Primo, viene specificato il numero di periodi che si desidera prevedere (variabile \(n\)). Successivamente, i dati del vostro portafoglio vengono suddivisi in una parte di training e una di test, utilizzando le prime \(n\) osservazioni come set di test. Il modello ARIMA viene quindi addestrato utilizzando i dati di training e viene effettuata la previsione per il set di test. Infine, viene generato un grafico che mostra le previsioni del modello e i dati di test, consentendo di valutare l’accuratezza delle previsioni del modello. In questo modo, potrete utilizzare il modello ARIMA per fare previsioni sulle performance future del vostro portafoglio e prendere decisioni informate su come allocare il vostro portafoglio in futuro.

# Number of period we want to forecast
n <- 100

# Splitting the data
train <- head(Cl(myPortfolio), length(Cl(myPortfolio))-n)
test <- tail(Cl(myPortfolio), n)

library(forecast)
# Forecast the data
fc_na <- forecast(auto.arima(train), h=n)

# Plot the result
autoplot(fc_na) +
  autolayer(ts(test, start=length(train)), series = "Test Data")

5.1.1 Più in dettaglio sugli ARIMA

Il modello ARIMA (Auto-Regressive Integrated Moving Average) è una combinazione di modelli autoregressivi, di integrazione di differenziazione e di media mobile. Il modello autoregressivo (AR) definisce il rapporto tra un’osservazione e alcune osservazioni con ritardo. Per utilizzare il modello ARIMA, i dati delle serie temporali devono diventare stazionari e ciò può essere ottenuto effettuando la differenza dei dati. Infine, il modello di media mobile (MA) definisce il rapporto tra un’osservazione e l’errore residuo del modello di media mobile sulle osservazioni con ritardo.

I modelli ARIMA vengono generalmente indicati con ARIMA (\(p, d, q\)), dove \(p\), \(d\) e \(q\) sono i parametri con valori positivi. L’ordine di AR (\(p\)) è il numero di osservazioni con ritardo nel modello. Per la differenziazione, abbiamo d come numero di volte in cui i dati effettivi vengono differenziati per diventare stazionari. Di solito, il massimo numero di differenziazioni per ottenere la stazionarietà è 2 volte. L’ordine di MA (\(q\)) è la dimensione della finestra di media mobile.

Esistono modi per determinare i valori appropriati di questi parametri per il nostro modello, ma sono difficili. Fortunatamente, in R abbiamo la funzione auto.arima() che svolgerà questo lavoro per noi. Quando si utilizza questa funzione, esistono due tipi di ARIMA che possiamo ottenere: ARIMA non stagionale (quello che abbiamo discusso prima) e ARIMA stagionale. Ovviamente, nell’ARIMA non stagionale non includiamo la parte stagionale dei dati, mentre nell’ARIMA stagionale la includiamo. Vedremo quale dei due produca il miglior risultato di previsione per i nostri dati.