tickers <- c("NFLX", "AAPL", "LLY")
start_date <- as.Date("2023-10-01")
end_date <- as.Date("2025-11-05")
getSymbols(tickers, src = "yahoo", from = start_date, to = end_date)
## [1] "NFLX" "AAPL" "LLY"
prices <- merge(Ad(NFLX), Ad(AAPL), Ad(LLY))
colnames(prices) <- c("Netflix", "Apple", "Eli_Lilly")
prices_df <- data.frame(Date = index(prices), coredata(prices))
prices_melt <- melt(prices_df, id.vars = "Date")
ggplot(prices_melt, aes(x = Date, y = value, color = variable)) +
geom_line(size = 1) +
labs(title = "Histórico de precios (NFLX, AAPL, LLY)",
x = "Fecha", y = "Precio ajustado (USD)",
color = "Acción") +
theme_minimal()
prices <- merge(Ad(NFLX), Ad(AAPL), Ad(LLY))
colnames(prices) <- c("Netflix", "Apple", "Eli_Lilly")
returns <- na.omit(Return.calculate(prices))
mean_returns <- colMeans(returns)
cov_matrix <- cov(returns)
Dmat <- 2 * cov_matrix
dvec <- rep(0, length(mean_returns))
Amat <- cbind(rep(1, length(mean_returns)), diag(length(mean_returns)))
bvec <- c(1, rep(0, length(mean_returns))) # suma de pesos = 1, pesos >= 0
solution <- solve.QP(Dmat, dvec, Amat, bvec, meq = 1)
weights <- solution$solution
names(weights) <- colnames(prices)
weights
## Netflix Apple Eli_Lilly
## 0.2700488 0.4567437 0.2732075
total_investment <- 10000000
allocation <- weights * total_investment
allocation
## Netflix Apple Eli_Lilly
## 2700488 4567437 2732075
# Función para calcular riesgo y retorno dado un vector de pesos
portfolio_stats <- function(weights, mean_returns, cov_matrix) {
ret <- sum(weights * mean_returns)
risk <- sqrt(t(weights) %*% cov_matrix %*% weights)
return(c(risk, ret))
}
# Generar combinaciones de pesos para la frontera eficiente
n_points <- 100
weights_list <- matrix(NA, nrow = n_points, ncol = length(mean_returns))
returns_list <- numeric(n_points)
risk_list <- numeric(n_points)
for (i in 1:n_points) {
# Restricción: suma de pesos = 1, pesos >= 0
target_return <- min(mean_returns) + (max(mean_returns) - min(mean_returns)) * (i / n_points)
Dmat <- 2 * cov_matrix
dvec <- rep(0, length(mean_returns))
Amat <- cbind(rep(1, length(mean_returns)), mean_returns, diag(length(mean_returns)))
bvec <- c(1, target_return, rep(0, length(mean_returns)))
result <- solve.QP(Dmat, dvec, Amat, bvec, meq = 2)
weights_list[i, ] <- result$solution
stats <- portfolio_stats(result$solution, mean_returns, cov_matrix)
risk_list[i] <- stats[1]
returns_list[i] <- stats[2]
}
# Data frame para graficar
frontier_df <- data.frame(Risk = risk_list, Return = returns_list)
# Portafolio actual (mínima varianza)
current_stats <- portfolio_stats(weights, mean_returns, cov_matrix)
# Gráfico
ggplot(frontier_df, aes(x = Risk, y = Return)) +
geom_line(color = "blue", linewidth = 1.2) +
geom_point(aes(x = current_stats[1], y = current_stats[2]), color = "red", size = 3) +
labs(title = "Frontera Eficiente y Portafolio Actual",
x = "Riesgo (Desviación Estándar)",
y = "Retorno Esperado") +
theme_minimal()
# Parámetros de simulación GBM
set.seed(123)
n_sim <- 500 # número de trayectorias
n_days <- 252 * 2 # dos años
dt <- 1/252
# Últimos precios y volatilidades
S0 <- as.numeric(last(prices))
mu <- colMeans(returns)
sigma <- apply(returns, 2, sd)
# Función de simulación MGB
sim_prices <- function(S0, mu, sigma, n_days, n_sim) {
matrix(S0 * exp(cumsum((mu - 0.5 * sigma^2) * dt +
sigma * sqrt(dt) * matrix(rnorm(n_days * n_sim), nrow = n_days))),
nrow = n_days, ncol = n_sim)
}
# Simular precios para cada acción
sim_list <- lapply(1:3, function(i) sim_prices(S0[i], mu[i], sigma[i], n_days, n_sim))
names(sim_list) <- c("NFLX", "AAPL", "LLY")
# Visualizar trayectorias simuladas
plot_sim <- function(sim_matrix, name) {
matplot(sim_matrix[, 1:20], type = "l", lty = 1, col = rainbow(20),
main = paste("Simulación de precios futuros -", name),
xlab = "Días", ylab = "Precio simulado")
}
par(mfrow = c(1, 3))
plot_sim(sim_list$NFLX, "NFLX")
plot_sim(sim_list$AAPL, "AAPL")
plot_sim(sim_list$LLY, "LLY")
# Calcular valor del portafolio en cada simulación
# Usamos los pesos del portafolio (weights) y las simulaciones de cada acción
portfolio_values <- matrix(NA, nrow = n_days, ncol = n_sim)
for (i in 1:n_sim) {
for (t in 1:n_days) {
portfolio_values[t, i] <- sum(c(sim_list$NFLX[t, i],
sim_list$AAPL[t, i],
sim_list$LLY[t, i]) * weights)
}
}
# Verificar
dim(portfolio_values) # Debe ser 504 x 500 (2 años x simulaciones)
## [1] 504 500
# Análisis: valor final del portafolio
final_values <- portfolio_values[n_days, ]
summary(final_values)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 654.9 1153.4 1916.4 2614.8 3731.8 6894.9
# VaR al 1% y 5%
VaR_1 <- quantile(final_values, probs = 0.01)
VaR_5 <- quantile(final_values, probs = 0.05)
cat("VaR al 1%:", VaR_1, "\n")
## VaR al 1%: 669.9733
cat("VaR al 5%:", VaR_5, "\n")
## VaR al 5%: 696.2229
# Histograma con líneas de VaR
hist(final_values, breaks = 50, col = "lightblue",
main = "Distribución del valor final del portafolio",
xlab = "Valor del portafolio (USD)")
abline(v = VaR_1, col = "red", lwd = 2)
abline(v = VaR_5, col = "orange", lwd = 2)
legend("topright", legend = c("VaR 1%", "VaR 5%"),
col = c("red", "orange"), lwd = 2)
Tipo de opciones: Put: para proteger contra caídas (cobertura directa). Call vendidas: para generar ingresos si el precio no sube demasiado (estrategia de ingresos). Strike price: puede ser el precio actual o el promedio simulado. Modelo de valuación: Europeas: Black-Scholes. Americanas: Árbol binomial.
# Función para opción europea tipo call
BS_Call <- function(S, K, r, sigma, T){
d1 <- (log(S/K) + (r + 0.5*sigma^2)*T) / (sigma * sqrt(T))
d2 <- d1 - sigma * sqrt(T)
C <- S * pnorm(d1) - K * exp(-r * T) * pnorm(d2)
return(C)
}
# Función para opción europea tipo put
BS_Put <- function(S, K, r, sigma, T){
d1 <- (log(S/K) + (r + 0.5*sigma^2)*T) / (sigma * sqrt(T))
d2 <- d1 - sigma * sqrt(T)
P <- K * exp(-r * T) * pnorm(-d2) - S * pnorm(-d1)
return(P)
}
# Tasa del bono a 10 años
r <- 0.045
# Tiempo hasta vencimiento (trimestre)
T <- 0.25
# AAPL
S_AAPL <- 170 # Precio actual
K_AAPL <- 170 # Strike
sigma_AAPL <- 0.25 # Volatilidad
# NFLX
S_NFLX <- 400
K_NFLX <- 400
sigma_NFLX <- 0.30
# LLY
S_LLY <- 600
K_LLY <- 600
sigma_LLY <- 0.22
# AAPL
call_AAPL <- BS_Call(S_AAPL, K_AAPL, r, sigma_AAPL, T)
put_AAPL <- BS_Put(S_AAPL, K_AAPL, r, sigma_AAPL, T)
# NFLX
call_NFLX <- BS_Call(S_NFLX, K_NFLX, r, sigma_NFLX, T)
put_NFLX <- BS_Put(S_NFLX, K_NFLX, r, sigma_NFLX, T)
# LLY
call_LLY <- BS_Call(S_LLY, K_LLY, r, sigma_LLY, T)
put_LLY <- BS_Put(S_LLY, K_LLY, r, sigma_LLY, T)
# Mostrar resultados
cat("AAPL - Call:", call_AAPL, " Put:", put_AAPL, "\n")
## AAPL - Call: 9.409563 Put: 7.50778
cat("NFLX - Call:", call_NFLX, " Put:", put_NFLX, "\n")
## NFLX - Call: 26.08447 Put: 21.60969
cat("LLY - Call:", call_LLY, " Put:", put_LLY, "\n")
## LLY - Call: 29.66241 Put: 22.95024
# Función para opción americana tipo PUT con árbol binomial
binomial_tree_american_put <- function(S, K, r, sigma, T, steps) {
dt <- T / steps
u <- exp(sigma * sqrt(dt))
d <- 1 / u
p <- (exp(r * dt) - d) / (u - d)
# Árbol de precios
prices <- matrix(0, nrow = steps + 1, ncol = steps + 1)
for (i in 0:steps) {
for (j in 0:i) {
prices[j + 1, i + 1] <- S * u^j * d^(i - j)
}
}
# Árbol de valores de opción
option <- matrix(0, nrow = steps + 1, ncol = steps + 1)
for (j in 0:steps) {
option[j + 1, steps + 1] <- max(K - prices[j + 1, steps + 1], 0)
}
# Retroceso en el árbol
for (i in (steps - 1):0) {
for (j in 0:i) {
hold <- exp(-r * dt) * (p * option[j + 2, i + 2] + (1 - p) * option[j + 1, i + 2])
exercise <- max(K - prices[j + 1, i + 1], 0)
option[j + 1, i + 1] <- max(hold, exercise)
}
}
return(option[1, 1])
}
# Parámetros de prueba
S <- 170 # Precio actual
K <- 170 # Strike
r <- 0.045 # Tasa libre de riesgo
sigma <- 0.25 # Volatilidad
T <- 0.25 # Tiempo en años
steps <- 100 # Pasos del árbol
# Ejecutar función
binomial_tree_american_put(S, K, r, sigma, T, steps)
## [1] 7.650303
# Parámetros generales
r <- 0.045
T <- 0.25
steps <- 100
# AAPL
put_AAPL <- binomial_tree_american_put(S = 170, K = 170, r = r, sigma = 0.25, T = T, steps = steps)
# NFLX
put_NFLX <- binomial_tree_american_put(S = 400, K = 400, r = r, sigma = 0.30, T = T, steps = steps)
# LLY
put_LLY <- binomial_tree_american_put(S = 600, K = 600, r = r, sigma = 0.22, T = T, steps = steps)
# Mostrar resultados
cat("AAPL - Put americana:", put_AAPL, "\n")
## AAPL - Put americana: 7.650303
cat("NFLX - Put americana:", put_NFLX, "\n")
## NFLX - Put americana: 21.92848
cat("LLY - Put americana:", put_LLY, "\n")
## LLY - Put americana: 23.47025
U.S. Department of the Treasury. (2025). Daily Treasury Yield Curve Rates. https://home.treasury.gov/resource-center/data-chart-center/interest-rates