# Installation et chargement des packages nécessaires
library(quantmod)
## Warning: le package 'quantmod' a été compilé avec la version R 4.2.3
## Le chargement a nécessité le package : xts
## Warning: le package 'xts' a été compilé avec la version R 4.2.3
## Le chargement a nécessité le package : zoo
## Warning: le package 'zoo' a été compilé avec la version R 4.2.3
## 
## Attachement du package : 'zoo'
## Les objets suivants sont masqués depuis 'package:base':
## 
##     as.Date, as.Date.numeric
## Le chargement a nécessité le package : TTR
## Warning: le package 'TTR' a été compilé avec la version R 4.2.3
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
library(PerformanceAnalytics)
## Warning: le package 'PerformanceAnalytics' a été compilé avec la version R
## 4.2.3
## 
## Attachement du package : 'PerformanceAnalytics'
## L'objet suivant est masqué depuis 'package:graphics':
## 
##     legend
library(ggplot2)
## Warning: le package 'ggplot2' a été compilé avec la version R 4.2.3
library(tidyverse)
## Warning: le package 'tidyverse' a été compilé avec la version R 4.2.3
## Warning: le package 'tibble' a été compilé avec la version R 4.2.3
## Warning: le package 'tidyr' a été compilé avec la version R 4.2.3
## Warning: le package 'readr' a été compilé avec la version R 4.2.3
## Warning: le package 'purrr' a été compilé avec la version R 4.2.3
## Warning: le package 'dplyr' a été compilé avec la version R 4.2.3
## Warning: le package 'stringr' a été compilé avec la version R 4.2.3
## Warning: le package 'forcats' a été compilé avec la version R 4.2.3
## Warning: le package 'lubridate' a été compilé avec la version R 4.2.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ lubridate 1.9.3     ✔ tibble    3.2.1
## ✔ purrr     1.0.2     ✔ tidyr     1.3.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::first()  masks xts::first()
## ✖ dplyr::lag()    masks stats::lag()
## ✖ dplyr::last()   masks xts::last()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(TTR)
library(knitr)
library(rmarkdown)
# Définition des paramètres
montant_initial <- 10000
poids <- c(0.15, 0.20, 0.30, 0.35)
tickers <- c("AI.PA", "OR.PA", "SU.PA", "MC.PA")  # Air Liquide, L'Oréal, Schneider, LVMH
date_debut <- Sys.Date() - years(3)
date_fin <- Sys.Date()
stop_loss_pct <- 0.05  # Stop loss à 5%
trailing_stop_pct <- 0.08  # Trailing stop à 8%

# Téléchargement des données
getSymbols(tickers, from = date_debut, to = date_fin, src = "yahoo")
## [1] "AI.PA" "OR.PA" "SU.PA" "MC.PA"
getSymbols("^FCHI", from = date_debut, to = date_fin, src = "yahoo")
## [1] "FCHI"
# Fonction originale pour appliquer le stop loss
apply_stop_loss <- function(prices) {
  prices_clean <- na.omit(as.numeric(prices))
  n <- length(prices_clean)
  positions <- numeric(n)
  positions[1] <- 1
  
  current_stop <- prices_clean[1] * (1 - stop_loss_pct)
  trailing_stop <- prices_clean[1] * (1 - trailing_stop_pct)
  highest_price <- prices_clean[1]
  in_trade <- TRUE
  wait_days <- 0
  
  for(i in 2:n) {
    if(in_trade) {
      if(prices_clean[i] > highest_price) {
        highest_price <- prices_clean[i]
        trailing_stop <- highest_price * (1 - trailing_stop_pct)
      }
      
      if(prices_clean[i] < current_stop || prices_clean[i] < trailing_stop) {
        positions[i] <- 0
        in_trade <- FALSE
        wait_days <- 5
        cat("Stop triggered at price:", prices_clean[i], "\n")
      } else {
        positions[i] <- 1
      }
    } else {
      if(wait_days > 0) {
        positions[i] <- 0
        wait_days <- wait_days - 1
      } else {
        positions[i] <- 1
        in_trade <- TRUE
        current_stop <- prices_clean[i] * (1 - stop_loss_pct)
        highest_price <- prices_clean[i]
        trailing_stop <- highest_price * (1 - trailing_stop_pct)
        cat("Re-entry at price:", prices_clean[i], "\n")
      }
    }
  }
  
  xts(positions, order.by=index(prices))
}

# Création du portefeuille
portfolio_data <- list()
for(i in 1:length(tickers)) {
  portfolio_data[[i]] <- Ad(get(tickers[i]))
}
portfolio_prices <- do.call(merge, portfolio_data)
colnames(portfolio_prices) <- tickers

# Calcul des rendements de base
returns <- na.omit(Return.calculate(portfolio_prices))

# Application des stop loss pour chaque titre
stop_loss_signals <- matrix(NA, nrow=nrow(returns), ncol=ncol(returns))
colnames(stop_loss_signals) <- colnames(returns)

for(i in 1:ncol(portfolio_prices)) {
  signals <- apply_stop_loss(portfolio_prices[,i])
  stop_loss_signals[,i] <- as.numeric(signals[index(returns)])
}
## Stop triggered at price: 107.8007 
## Re-entry at price: 118.2816 
## Stop triggered at price: 121.3158 
## Re-entry at price: 115.1044 
## Stop triggered at price: 107.4191 
## Re-entry at price: 110.4371 
## Stop triggered at price: 109.8405 
## Re-entry at price: 107.4191 
## Stop triggered at price: 101.5059 
## Re-entry at price: 103.1729 
## Stop triggered at price: 136.3538 
## Re-entry at price: 142.7507 
## Stop triggered at price: 159.28 
## Re-entry at price: 164.76 
## Stop triggered at price: 161.5 
## Re-entry at price: 160.24 
## Stop triggered at price: 309.9063 
## Re-entry at price: 339.7831 
## Stop triggered at price: 322.7444 
## Re-entry at price: 319.3474 
## Stop triggered at price: 302.5901 
## Re-entry at price: 313.8893 
## Stop triggered at price: 295.552 
## Re-entry at price: 311.0166 
## Stop triggered at price: 295.2168 
## Re-entry at price: 302.2071 
## Stop triggered at price: 323.848 
## Re-entry at price: 330.6467 
## Stop triggered at price: 311.9742 
## Re-entry at price: 312.836 
## Stop triggered at price: 296.9404 
## Re-entry at price: 304.601 
## Stop triggered at price: 288.2266 
## Re-entry at price: 332.083 
## Stop triggered at price: 315.9959 
## Re-entry at price: 324.3268 
## Stop triggered at price: 392.9566 
## Re-entry at price: 396.2559 
## Stop triggered at price: 385.5702 
## Re-entry at price: 385.9149 
## Stop triggered at price: 412.4567 
## Re-entry at price: 434.6159 
## Stop triggered at price: 406.4491 
## Re-entry at price: 409.1575 
## Stop triggered at price: 410.05 
## Re-entry at price: 405.45 
## Stop triggered at price: 381.05 
## Re-entry at price: 376.65 
## Stop triggered at price: 365.2 
## Re-entry at price: 370.5 
## Stop triggered at price: 368.2 
## Re-entry at price: 358.7 
## Stop triggered at price: 337.7 
## Re-entry at price: 329.8 
## Stop triggered at price: 333.95 
## Stop triggered at price: 127.3353 
## Re-entry at price: 122.3332 
## Stop triggered at price: 134.961 
## Re-entry at price: 139.057 
## Stop triggered at price: 131.2048 
## Re-entry at price: 123.6356 
## Stop triggered at price: 115.0472 
## Re-entry at price: 124.5017 
## Stop triggered at price: 115.5397 
## Re-entry at price: 110.5952 
## Stop triggered at price: 120.4263 
## Re-entry at price: 114.3422 
## Stop triggered at price: 114.4388 
## Re-entry at price: 109.2432 
## Stop triggered at price: 126.3366 
## Re-entry at price: 127.9397 
## Stop triggered at price: 139.5478 
## Re-entry at price: 144.7434 
## Stop triggered at price: 137.4232 
## Re-entry at price: 145.9988 
## Stop triggered at price: 137.964 
## Re-entry at price: 146.192 
## Stop triggered at price: 150.6679 
## Re-entry at price: 151.5546 
## Stop triggered at price: 143.5936 
## Re-entry at price: 140.9531 
## Stop triggered at price: 216.05 
## Re-entry at price: 203.5 
## Stop triggered at price: 245 
## Re-entry at price: 238.8 
## Stop triggered at price: 603.2485 
## Re-entry at price: 548.1318 
## Stop triggered at price: 583.9908 
## Re-entry at price: 576.2183 
## Stop triggered at price: 539.1793 
## Re-entry at price: 551.7495 
## Stop triggered at price: 527.7604 
## Re-entry at price: 531.1188 
## Stop triggered at price: 621.3179 
## Re-entry at price: 617.4796 
## Stop triggered at price: 578.8091 
## Re-entry at price: 583.4151 
## Stop triggered at price: 795.5875 
## Re-entry at price: 784.5851 
## Stop triggered at price: 788.6745 
## Re-entry at price: 789.8429 
## Stop triggered at price: 739.1146 
## Re-entry at price: 710.3912 
## Stop triggered at price: 680.3048 
## Re-entry at price: 701.6282 
## Stop triggered at price: 657.2288 
## Re-entry at price: 646.5184 
## Stop triggered at price: 668.0336 
## Re-entry at price: 635.3532 
## Stop triggered at price: 784.9173 
## Re-entry at price: 780.0103 
## Stop triggered at price: 738.4807 
## Re-entry at price: 745.6138 
## Stop triggered at price: 704.7963 
## Re-entry at price: 719.7561 
## Stop triggered at price: 680.5237 
## Re-entry at price: 683.7931 
## Stop triggered at price: 646.5421 
## Re-entry at price: 624.6473 
## Stop triggered at price: 613.4521 
## Re-entry at price: 602.4551 
## Stop triggered at price: 631.8795 
## Re-entry at price: 610.2819 
## Stop triggered at price: 567.0866 
## Re-entry at price: 570.0588 
## Stop triggered at price: 690.1 
## Re-entry at price: 685.2
# Création des rendements avec stop loss
returns_with_stops <- returns * stop_loss_signals

# Calcul des rendements pondérés
portfolio_returns_no_stop <- Return.portfolio(returns, weights = poids)
portfolio_returns_with_stops <- Return.portfolio(returns_with_stops, weights = poids)

# Synchronisation avec le CAC40
cac40_returns <- Return.calculate(Ad(FCHI))
cac40_returns <- cac40_returns[index(returns)]

# Comparaison finale
comparison <- merge(portfolio_returns_no_stop, portfolio_returns_with_stops, cac40_returns)
colnames(comparison) <- c("Sans_Stop", "Avec_Stop", "CAC40")

# Calcul des performances cumulées
cumul_returns <- cumprod(1 + comparison)

# Fonction de calcul des statistiques de performance
performance_stats <- function(returns, cumul_rets) {
  returns_num <- as.numeric(returns)
  total_return <- (tail(as.numeric(cumul_rets), 1) - 1) * 100
  vol <- sd(returns_num, na.rm = TRUE) * sqrt(252) * 100
  sharpe <- (mean(returns_num, na.rm = TRUE) - 0.02/252) / sd(returns_num, na.rm = TRUE) * sqrt(252)
  dd <- cumul_rets/cummax(cumul_rets) - 1
  max_dd <- min(dd) * 100
  
  c("Rendement total (%)" = total_return,
    "Volatilité ann. (%)" = vol,
    "Ratio de Sharpe" = sharpe,
    "Max Drawdown (%)" = max_dd)
}

# Calcul des statistiques pour chaque stratégie
stats_sans_stop <- performance_stats(comparison$Sans_Stop, cumul_returns$Sans_Stop)
stats_avec_stop <- performance_stats(comparison$Avec_Stop, cumul_returns$Avec_Stop)
stats_cac40 <- performance_stats(comparison$CAC40, cumul_returns$CAC40)

# Création du tableau de performance
perf_table <- data.frame(
  "Sans Stop-Loss" = stats_sans_stop,
  "Avec Stop-Loss" = stats_avec_stop,
  "CAC40" = stats_cac40
)

# Statistiques de trading
trades_count <- colSums(abs(diff(stop_loss_signals))) / 2

# Affichage des résultats
cat("\n=== STATISTIQUES DE PERFORMANCE ===\n")
## 
## === STATISTIQUES DE PERFORMANCE ===
print(round(perf_table, 2))
##                     Sans.Stop.Loss Avec.Stop.Loss  CAC40
## Rendement total (%)          34.33         114.98  17.37
## Volatilité ann. (%)          21.94          18.97  16.58
## Ratio de Sharpe               0.46           1.32   0.28
## Max Drawdown (%)            -18.57         -11.22 -18.67
cat("\n=== STATISTIQUES DE TRADING ===\n")
## 
## === STATISTIQUES DE TRADING ===
trades_summary <- data.frame(
  Titre = names(trades_count),
  NbTrades = trades_count,
  TradesParMois = round(trades_count / (nrow(comparison)/21), 1),
  "% du Total" = round(trades_count/sum(trades_count)*100, 1)
)
print(trades_summary)
##       Titre NbTrades TradesParMois X..du.Total
## AI.PA AI.PA      8.0           0.2        12.6
## OR.PA OR.PA     19.5           0.5        30.7
## SU.PA SU.PA     15.0           0.4        23.6
## MC.PA MC.PA     21.0           0.6        33.1
# Graphique
plot_data <- data.frame(
  Date = index(cumul_returns),
  Sans_Stop = coredata(cumul_returns[,1]),
  Avec_Stop = coredata(cumul_returns[,2]),
  CAC40 = coredata(cumul_returns[,3])
)

ggplot(plot_data, aes(x = Date)) +
  geom_line(aes(y = Sans_Stop, color = "Sans Stop-Loss"), linewidth = 1) +
  geom_line(aes(y = Avec_Stop, color = "Avec Stop-Loss"), linewidth = 1) +
  geom_line(aes(y = CAC40, color = "CAC40"), linewidth = 1) +
  labs(title = "Performance comparée: Stratégies vs CAC40",
       x = "Date",
       y = "Valeur relative (base 1)",
       color = "Stratégies") +
  theme_minimal() +
  scale_color_manual(values = c("Sans Stop-Loss" = "blue", 
                                "Avec Stop-Loss" = "green",
                                "CAC40" = "red")) +
  theme(legend.position = "bottom")