hi, I wrote a few utility function and a main function that compute portfolio weights for a set of inputs which the user select and a few more characteristics for graphical representation. The functions in R work perfectly fine and give a list of matrix/ vectors and a data frame.
here is the code with a dput() of some of the data :
DONNEE<-data.frame(c(structure(list(Name = structure(c(552787200, 552873600, 553132800,
553219200, 553305600, 553392000, 553478400, 553737600, 553824000,
553910400, 553996800, 554083200, 554342400, 554428800, 554515200,
554601600, 554688000, 554947200, 555033600, 555120000, 555206400,
555292800, 555552000, 555638400, 555724800, 555811200, 555897600,
556156800, 556243200, 556329600, 556416000, 556502400, 556761600,
556848000, 556934400, 557020800, 557107200, 557366400, 557452800,
557539200, 557625600, 557712000, 557971200, 558057600, 558144000,
558230400, 558316800, 558576000, 558662400, 558748800), class = c("POSIXct",
"POSIXt"), tzone = "UTC"), ACCOR...PRICE.INDEX...E.. = c(118.8,
118.3, 118.3, 118.3, 118.3, 116.3, 116.3, 116.1, 113.1, 114.6,
116.3, 120.1, 119.6, 118.6, 119.3, 119.1, 118.8, 117.8, 115.2,
116.3, 117.6, 117.3, 116.8, 116.4, 116.3, 116.2, 117.1, 117.9,
115.7, 113.9, 114.8, 116.2, 116.9, 116.6, 119.6, 120.3, 122.3,
124.6, 125.1, 127.1, 126.8, 124.1, 118.1, 120.6, 118.9, 120.6,
118.6, 118.6, 117.3, 116.1), AIR.LIQUIDE...PRICE.INDEX...E.. = c(1231.7,
1228.1, 1228.1, 1228.1, 1228.1, 1200, 1212.3, 1208.8, 1191.3,
1177.2, 1177.2, 1196.5, 1198.3, 1201.8, 1203.5, 1229.9, 1229.9,
1229.9, 1203.5, 1203.5, 1198.3, 1207.1, 1194.8, 1189.5, 1191.3,
1198.3, 1224.6, 1226.4, 1208.8, 1203.5, 1187.7, 1186, 1208.8,
1179, 1228.1, 1235.2, 1240.4, 1236.9, 1229.9, 1222.9, 1203.5,
1210.6, 1198.3, 1191.3, 1182.5, 1184.2, 1180.7, 1184.2, 1186,
1184.2), ALCATEL.LUCENT...PRICE.INDEX...E.. = c(103.1, 103.7,
103.7, 103.7, 103.7, 102.2, 101.2, 100, 101.5, 100.6, 100.6,
102.1, 102.2, 102.5, 104.2, 105.2, 106.5, 107.4, 105.9, 105.3,
106.2, 105.6, 105.9, 105.9, 105.3, 105.3, 105.3, 106.8, 106.2,
105.5, 104.8, 103.7, 104.7, 105, 106.3, 106.8, 106.5, 106.7,
105.6, 104.6, 104.6, 104.4, 104.2, 104.2, 103.1, 103.6, 103.4,
104.2, 104.3, 104.6), AXA...PRICE.INDEX...E.. = c(2097.8, 2105.2,
2105.2, 2105.2, 2084.3, 2047, 1993.2, 1975.3, 1960.4, 1963.4,
1955.9, 1978.3, 1972.3, 1955.9, 1951.4, 1936.5, 1941, 1955.9,
1900.7, 1881.3, 1891.7, 1858.9, 1851.4, 1858.9, 1772.3, 1899.2,
1903.7, 1896.2, 1854.4, 1809.6, 1826, 1851.4, 1851.4, 1858.9,
1918.6, 1954.4, 2003.7, 2021.6, 2015.6, 1969.4, 1978.3, 1985.8,
2012.7, 2015.6, 2020.1, 2072.4, 2067.9, 2082.8, 2066.4, 2067.9
), BOUYGUES...PRICE.INDEX...E.. = c(2251.1, 2290.1, 2290.1, 2290.1,
2290.1, 2181, 2182.9, 2173.2, 2128.3, 2202.4, 2251.1, 2344.7,
2290.1, 2358.3, 2418.7, 2372, 2391.5, 2368.1, 2274.5, 2270.6,
2260.9, 2307.7, 2311.6, 2329.1, 2338.8, 2323.2, 2354.4, 2348.6,
2338.8, 2327.1, 2356.4, 2336.9, 2340.8, 2348.6, 2412.9, 2407.1,
2397.3, 2416.8, 2397.3, 2416.8, 2438.2, 2455.8, 2418.7, 2414.9,
2393.4, 2426.5, 2426.5, 2387.6, 2338.8, 2327.1), CAP.GEMINI...PRICE.INDEX...E.. = c(299.9,
299.9, 299.9, 299.9, 299.9, 298.9, 296.7, 298.3, 298.2, 296.3,
293, 287.3, 302.1, 304.9, 327.7, 321.9, 315.4, 310.4, 307.2,
303.1, 308.5, 307.2, 309.7, 307.4, 307.2, 305.9, 311, 309.9,
309.1, 307.4, 308.2, 316, 320, 312.3, 320.1, 322.5, 319.8, 318.9,
320, 318.2, 318.1, 317.4, 316.1, 311, 309.1, 313.6, 309.7, 308.5,
307.2, 312.3), CARREFOUR...PRICE.INDEX...E.. = c(496.3, 495.6,
495.6, 495.6, 493.4, 490.5, 462.8, 461.6, 461.9, 468.6, 469.8,
474.5, 469.2, 471.4, 473.7, 470.2, 478.1, 467.2, 465, 467.9,
475.9, 470.8, 469.4, 457, 465, 473.6, 479.6, 486.1, 481, 479.6,
477.4, 484.1, 492.8, 502.1, 510.2, 518.8, 521.1, 523.1, 518.9,
517.5, 524, 532, 523.1, 517.6, 513.1, 511.5, 506.1, 504.3, 502.9,
491.9), CAC.40...PRICE.INDEX = c(1482.89, 1490.42, 1490.42, 1490.42,
1490.42, 1474.22, 1462.11, 1457.38, 1444.71, 1446.65, 1461.3,
1483.55, 1478.54, 1484.7, 1494.49, 1488.41, 1488.31, 1483.02,
1460.73, 1460.39, 1473.59, 1467.85, 1458.24, 1450.97, 1450.81,
1458.7, 1486.49, 1487.29, 1471.36, 1461.47, 1466.13, 1471.44,
1490.7, 1485.92, 1514.55, 1526.59, 1528.97, 1533.59, 1530.11,
1524, 1550.52, 1560.7, 1535.26, 1531.28, 1522.04, 1530.55, 1530.91, 1537.29, 1528.85, 1520.4)), row.names = c(NA, 50L), class = "data.frame")))
T<-nrow(DONNEE)
Pt_mat<-data.matrix(DONNEE[,2:(length(DONNEE)-1)])
Rt_mat<-Pt_mat[2:T,]/Pt_mat[1:T-1,]-1
Ptbench_mat<-data.matrix(DONNEE[,length(DONNEE)])
Rtbench_mat<-Ptbench_mat[2:T,]/Ptbench_mat[1:T-1,]-1
VCV_mat<-cov(Rt_mat)
datesALL<-DONNEE[,1]
dt<-(datesALL[2:T]-datesALL[1:T-1])/365
freq<-260
Rf<-0.03
VCV_mat<-cov(Rt_mat)
#### rendements annualises ####
ER<-(1+colMeans(Rt_mat))^(freq)-1 # rendements annualisé des actifs er E(Ri)
ERm<-(1+mean(Rtbench_mat))^(freq)-1
#### rendements geometriques ####
ERg<-(Pt_mat[T,]/Pt_mat[1,])^(freq/T)-1 # rendements géométrique annualisé des actifs er E(Ri)
ERmg<-(Ptbench_mat[T]/Ptbench_mat[1])^(freq/T)-1 # celui du marche
# RETOURNE LES ALPHA, BETA ET ECART TYPE DU RESIDUS
CAPM_estim <- function(Rt,Rf,Rm,freq,ER,ERm,N) {
# Rf valeur annuel
Xcapm<-Rt-((1+Rf)^(1/freq)-1) # excess return vs taux sans risque
Y=Rm-((1+Rf)^(1/freq)-1) # excess return du marche vs taux sans risque
bi=matrix(0,N,1) # vecteur des beta ivs marche
sei<-matrix(0,N,1) # vecteur des ecart-type du résidu
for (i in 1:N) {
model<-lm(Xcapm[,i]~Y)
b=coef(model)
e=residuals(model)
bi[i]<-b[2]
sei[i]<-sd(e)*sqrt(freq)
}
# calcul des alphas
ai<-ER-(Rf+(ERm-Rf)*bi) # alpha de chaque actifs
return(cbind(ai,bi,sei))
}
portf_equi <- function(N) {
wequi<-matrix(1/N,N,1)
return(wequi)
}
portf_actifsureval <- function(Rf,ER,ERm,bi) {
ERth<-Rf+(ERm-Rf)*bi
idx<-ER<ERth # = 1 si les actifs sont surévalués
Wb<-matrix(1/sum(idx),N,1)*idx # vecteur des poids du portefeuille equi ponderé des actifs surevalué
return(Wb)
}
portf_actifsouseval <- function(Rf,ER,ERm,bi) {
ERth<-Rf+(ERm-Rf)*bi
idxS<-ER>=ERth# =1 si les actifs sont sous evalué
Ws<-matrix(1/sum(idxS),N,1)*idxS # vecteur des poids du portefeuille equi ponderé des actifs sousevalué
return(Ws)
}
portf_maxinfo <- function(ai,sei,N) {
Dsei<-matrix(0,N,N) # matrice diagonale des risques individuel
diag(Dsei)<-sei^2
# calcul des poids avec Z
Z<-solve(Dsei)%*%ai
Wmaxinfo<-Z/sum(Z)
return(Wmaxinfo)
}
portf_minivar <- function(Rt,freq,ER,N) {
Un<-rep(1,N) # vecteur unitaire longueur N
VCV<-cov(Rt)*freq # matrice variance covariance annualisé sur la période
c<-t(Un)%*%solve(VCV)%*%Un
WV<-solve(VCV)%*%Un%*%(1/c) # poids des actifs dans le portefeuille minimum variance
return(WV)
}
portf_tangent <- function(Rt,freq,ER,Rf,N) {
Un<-rep(1,N) # vecteur unitaire longueur N
VCV<-cov(Rt)*freq # matrice variance covariance annualisé sur la période
Ex<-ER-Rf
ax<-t(Un)%*%solve(VCV)%*%Ex
WT<-solve(VCV)%*%Ex%*%(1/ax)
return(WT)
}
rentabiliteportf <- function(poids,Rt) {
# donne les rendements du portefeuille
Rtp<-Rt%*%poids#-managefee*dt # POUR METTRE LES FRAIS DE GESTION
return(Rtp)
}
prixportf100 <- function(rentabilite) {
# donne le prix base 100 a t0
Ptp<-100*cumprod(1+c(0,rentabilite))
return(Ptp)
}
frontiereefficiente <- function(Pt,Rt,freq,const,N,VCV) {
# la variable const est une matrice des seuils des contraintes par lignes avec sur la première
#colonnes les contraintes min et sur la deuxième les contraintes max
library(lpSolve)
library(quadprog)
# traitement pour l'optimiseur (contraintes)
# voir l'aide de la fonction lp pour faire le systeme d'optimisation
# etape 1 trouver l'esperance de rentabilité minimal
Ui<-matrix(0,N,N)
diag(Ui)<-1 # matrice identité NxN
U<-rbind(rep(1,N),Ui,Ui) # matrice des contraintes (A sur la feuille)
#C<-c(1,rep(0,N),rep(0.15,N)) # vecteur des contraintes (C sur la feuille)
C<-c(1,const[,1],const[,2]) # vecteur des contraintes (C sur la feuille)
direction<-c("=",rep(">=",N),rep("<=",N)) # vecteur des directions pour la fonction lp()
E<- (Pt[T,]/Pt[1,])^(freq/T)-1 # vecteur des rendements annualisé des actifs
f_obj=t(E)
f_con=U
f_dir=direction
f_rhs<-C
Ws<-lp (direction = "min", f_obj, f_con, f_dir, f_rhs)
wmin<-Ws$solution
Emin=t(wmin)%*%E
# etape 2 trouver L' E(Rp) max
Ws<-lp(direction = "max",f_obj, f_con, f_dir, f_rhs)
wmax<-Ws$solution
Emax=t(wmax)%*%E
# etape 3 creer une serie de rentabilité entre E min et E max avec un pas que l'on choisi en fct
# du nb de point qu'on veut
nbpoint<-100 # nombre d'iteration pour la frontiere
Ebar<-seq(Emin,Emax,(Emax-Emin)/(nbpoint-1) )
std<-rep(0,nbpoint)
std[1]<-sqrt(wmin%*%VCV%*%wmin*freq)
std[nbpoint]<-sqrt(wmax%*%VCV%*%wmax*freq)
# etape 4 minimer la variance pour chaque valeur de la série de rentabilité qu'on vient de créer
# voir l'aide pour solveQP pour optimiser les fonction quadratique
Dmat<-VCV
dvec<-rep(0,N)
A<- rbind(E,rep(1,N),Ui,-Ui)
bvec<-c(0,1,const[,1],-const[,2])
for (i in 2:(nbpoint-1)) {
bvec[1]<-Ebar[i]
S<-solve.QP(Dmat,dvec,t(A),bvec,meq = 2)
W<-S$solution
Ebar[i]<-t(W)%*%E
std[i]<-sqrt(t(W)%*%VCV%*%W*freq)
}
return(data.frame(cbind(Ebar,std)))
}
FNprtfcarac<-function(w,ER,VCV){# w: poids portefeuille ; ER rendements annualisé des actifs ; VCV : matrice de variance-covariance
Ebar<-t(w)%*%ER
std<-sqrt(t(w)%*%VCV%*%w*freq)
return(data.frame(cbind(Ebar,std)))
}
graphfronteff <- function(fronteffcarac,prtfcarac) {
return(ggplot(fronteffcarac)+geom_point(aes(std,Ebar))+geom_point(aes(X2,X1),data = prtfcarac))
}
graphevolprix100 <- function(Pt100) {
matplot(Pt100,type = "l")
legend("topleft",c("CAC40","equipondéré","sous evalué","surevalué"),col=c(1,2,3,4),lty=c(1,1,1,1))
title("Evolution des prix des différentes stratégies")
}
MAIN <- function(actifs,chxopt,geom) {
N<-length(actifs)
Ptmain<-Pt_mat[,actifs]
Rtmain<-Rt_mat[,actifs]
VCV<-VCV_mat[actifs,actifs]
const<-cbind(rep(0,N),rep(0.15,N))
if (geom=="arithmétiques") {
ERmain<-ER[actifs]
ERbench<-ERm
}else{
ERmain<-ERg[actifs]
ERbench<-ERmg
}
CAPM<-CAPM_estim(Rtmain,Rf,Rtbench_mat,freq,ERmain,ERbench,N)
if (chxopt=="minvar") {
w<-portf_minivar(Rtmain,freq,ERmain,N)
}else{
if (chxopt=="max sharpe") {
w<-portf_tangent(Rtmain,freq,ERmain,Rf,N)
}else{
if (chxopt=="max info") {
w<-portf_maxinfo(CAPM[,1],CAPM[,3],N)
}else{
if (chxopt=="min tracking error") { #COMPLETER VERIFIER CEST LAQUELLE
w<-1
}else{
if (chxopt=="stock picking") { # COMPLETER SOUS EVAL SUR EVAL
w<-1
}else{
if (chxopt=="équipondéré") {
w<-portf_equi(N)
}else{
if (chxopt=="max alpha") { ### COMPLETER METHODE ALPHA
w<-1
}
}
}
}
}
}
}
fronteffcarac<-frontiereefficiente(Ptmain,Rtmain,freq,const,N,VCV)
Rtprtf<-rentabiliteportf(w,Rtmain)
Ptprtf<-prixportf100(Rtprtf)
caracprtf<-FNprtfcarac(w,ERmain,VCV)
pt100<-cbind(prixportf100(Rtbench_mat),Ptprtf)
return(list(w,Ptprtf,Rtprtf,caracprtf,pt100,fronteffcarac))
}
If you now run this you'll see that it work flawlessly :
actifs<-c(1:7)
chxopt<-"minvar"
geom<-"arithmétiques"
MAIN(actifs,chxopt,geom)->test
test[[1]]
then I want to incorporate this to a shiny app and I need it to be reactive and change whenever the user change the inputs so I need to use reactive()
but it seems to mess up and i can get to plot my results too :
library(shiny)
library(DT)
library(tidyverse)
###################################
# utilisateur interface
###################################
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("Optimisation de portefeuille"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel( # BOUTONS DU COTE
# METHODE
selectInput("chxOpt", label = "méthode d'optimisation :",
choices = c("minvar", "max sharpe", "max info", "min tracking error","stock picking","équipondéré")),
# POIDS MAX
sliderInput("maxPoids", label = " poids maximum des actifs:",
min = 0, max = 100, value = 100,post = "%", step = 1),
# FRAIS DE MANAGEMENT
sliderInput("managefee", label = "frais de gestion :",
min = 0, max = 100, value = 0,post = "%", step = 1),
# FRAIS DE SURPERFORMANCE
sliderInput("perffee", label = " frais de surperformance :",
min = 0, max = 100, value = 0,post = "%", step = 1),
# RENDEMENTS ANNUALISE
selectInput("geom","rendements annulalisés :",c("géométriques","arithmétiques"),selected = "arithmétiques"),
# VENTE A DECOUVERTE
selectInput("longshort"," autoriser la vente à découverte :",c("long only","longshort"),selected = "longshort")
),
# RESULTATS
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Actifs",checkboxGroupInput("actifs","choissisez vos actifs",choiceNames = c("Credit Agricole", "Teleperformance", "Hermes", "Safran", "Air Liquide",
"Carrefour", "TotalEnergies", "L'oreal", "Bouygues", "Sanofi",
"Axa", "Danone", "Pernod Ricard", "Lvmh", "Michelin", "Thales",
"Kering", "EssilorLuxottica", "Schneider Electric", "Veolia Environ.",
"Saint Gobain", "CapGemini", "Vinci", "Vivendi", "Publicis Groupe",
"Societe Generale", "Bnp Paribas", "Renault", "Orange", "Engie",
"Alstom", "Legrand SA", "Worldline", "Unibail Rodamco Wes", "Eurofins Scient.",
"Dassault Systemes", "Arcelor Mittal", "Stmicroelectronics",
"Airbus", "Stellantis"),choiceValues = seq(1,40),inline = TRUE,width = 700) ),
tabPanel("Plan moyenne/variance", plotOutput("fronteff")),
tabPanel("Evolution du prix", tableOutput("evoprix")),
tabPanel("Composition du portefeuille", dataTableOutput("poids"))
)
)
)
)
###################################
# server
###################################
# Define server logic
server <- function(input, output,session) {
portefeuille<-reactive(do.call(MAIN,list(input$actifs,input$chxopt,input$geom)))
#fronteffcarac<-reactive(do.call(frontiereefficiente(input$actifs))) # POTENTIELLEMENT AJOUTER DES INPUT DE CONTRAINTE
output$poids<-DT::renderDataTable({as.matrix(input$actifs)}) #({portefeuille()[[1]]})
output$fronteff <- renderPlot({
graphfronteff(portefeuille()[[6]],portefeuille()[[4]])
})
output$evoprix<-renderPlot(graphevolprix100(portefeuille()[[5]]))
}
# Run the application
shinyApp(ui = ui, server = server)
What is the proper way to do this ?
Best regards,