Primero quiero decir que he leído este post (Cómo calcular el futuro de la distribución de precios utilizando la volatilidad?) pero no ayuda mucho.
Aquí es lo que estoy tratando de hacer (valores no son reales)
Vamos a suponer que el último precio de esta seguridad es 20.85 y lo que yo estoy tratando de hacer es determinar, con base en la volatilidad, el rango en el que el precio debe ser en n días con X % de probabilidad.
En mi parcela vamos a suponer que la zona azul es una probabilidad de 41,5% y los dos pruple puntos en 20 días en el futuro. Estoy buscando una función que tome un diario al final del día el precio del tiempo de la serie, una probabilidad, y un número de día y de retorno de un rango de precio. Por ejemplo basado en mi parcela:
- En 10 días el precio debería estar entre 19.65 y 20.05 con 93.4% posibilidades
- En 20 días el precio debería estar entre las 20.20 y 21.50 con el 41,5% de posibilidades de que
Me gustaría ser capaz de hacer eso con una función como esta :
future_price_range(eod_prices_time_serie, nb_of_days, probability)
#with the first exemple it would look like this:
future_price_range(pcef_eod, 10, 0.934)
# And return
[1] 19.65 20.05
Basado en el post me estoy refiriendo a en la parte superior de esta pregunta, ya he conseguido hacer algo pero no estoy seguro de si estoy haciendo lo correcto:
library(quantmod)
library(PerformanceAnalytics)
# Retrieving daily prices from yahoo finance
pcef <- getSymbols("PCEF")
# Selecting only the column of adjusted prices
pcef_ad <- Ad(PCEF)
En el post que he enlazado en la parte superior de mi pregunta es, dijo : "La distribución del logaritmo del precio de una acción en n días, es una distribución normal con una media de registro(currentprice) ..."
# So i take the last price
tail(pcef_ad, 1)
# PCEF.Adjusted
# 2017-11-22 23.62
# And a convert it to log
mean_last_price_log <- log(23.62)
"... y la desviación estándar de la volatilidad∗(√n/365.2425) si usted está utilizando el calendario de días, y suponiendo que no hay dividendos y 0% de tasa de interés sin riesgo."
# I calculate daily returns
pcef_daily_return <- dailyReturn(pcef_ad)
# To calculate the standard dev of returns
sd(pcef_daily_return)
# [,1]
# 0.005932502
Ya estoy usando la volatilidad diaria de la devuelve supongo que no debe dividir n por 365.2425. Yo estoy en lo correcto acerca de esto ?
# Let's say we want the price range in 10 days
n <- 10
sd_pcef_daily_return <- 0.005932502 * sqrt(n)
lg_dist <- rnorm(n = 10000, mean = mean_last_price_log, sd = sd)
# I convert it back to USD
us_dist <- exp(log_dist)
hist(us_dist)
No estoy seguro de a qué número debo tomar para el parámetro n en rnorm. Tomé 10000 porque parece "suficiente", pero ¿cuál es la regla aquí ? Esto es lo que obtengo:
### making a function of this
future_price_range <- function(eod_prices, days, probability){
last_price <- tail(eod_prices,1)
mean_log_price <- log(last_price)
sd_daily_returns <- sd(dailyReturn(eod_prices)) * sqrt(days)
log_dist <- rnorm(n = 10000, mean = mean_log_price, sd = sd_daily_returns)
usd_dist <- exp(log_dist)
return(hist(usd_dist))
}
future_price_range(eod_prices = pcef_ad, days = 100)
Así que con 100 días de la probabilidad de tener un mayor/menor precio aumenta a medida que se esperaba:
Pero ahora estoy luchando para poner en práctica la "probabilidad" de parámetro en la función y devolver un vector de la 2 los precios de la gama.
Podría usted confirmar que yo no he hecho ningún error en mi código y ¿tiene usted alguna pista que me ayude a terminar.
También sería genial si pudiera salida el mismo tipo de diagrama que se utiliza al principio de este post. Creo que es necesario para calcular el rango de precios para cada uno de los días hasta la fecha de destino y uso de los datos para trazar en el gráfico, pero no tengo idea de cómo hacerlo.
Hay una última cosa que me gustaría hacer: me tome un fin de la jornada diaria de los precios de series de tiempo, me puse un número de días y me da un rango de precios para un conjunto de probabilidades:
function(price_data, nb_of_days)
99% 55.12 20.90
95% 54.34 21.36
90% 53.26 22.35
80% 49.78 24.12
... ... ...
10% ... ...
5% ... ...
1% ... ...
Cualquier ayuda sería muy apreciada. Muchas gracias de antemano.
EDIT : Respuesta de @vanguard2k (muchas Gracias !)
Hice un par de ajuste de @vanguard2k respuesta para hacer el código reproductible. Para más detalles, mira el post de abajo
library(PerformanceAnalytics)
library(quantmod)
library(ggplot2)
library(lubridate)
# Retrieving price data from yahoo
pcef <- getSymbols("PCEF", auto.assign = FALSE)
# Selecting only adjusted EOD prices
pcef_ad <- Ad(pcef)
# tail(pcef_ad)
# PCEF.Adjusted
# 2017-11-15 23.21980
# 2017-11-16 23.40866
# 2017-11-17 23.51800
# 2017-11-20 23.53000
# 2017-11-21 23.57000
# 2017-11-22 23.62000
# Computing daily returns
pcef_daily_returns <- dailyReturn(pcef_ad)
# tail(pcef_daily_returns)
# daily.returns
# 2017-11-15 -0.0004278567
# 2017-11-16 0.0081334892
# 2017-11-17 0.0046709639
# 2017-11-20 0.0005102900
# 2017-11-21 0.0016999149
# 2017-11-22 0.0021213831
# Annualized Standard Deviation of daily returns
sigma <- sd(pcef_daily_returns)*sqrt(365)
# Why do we set a mean of zero ???
mean <- 0
probability <- 0.95
# Last observed price as "S"
S <- coredata(tail(pcef_ad,1))[1,1]
# Number of days to "forecast" as "n"
n <- 10
upper.bounds <- qnorm(probability,mean=mean*(0:n)/365,sd=sigma*sqrt((0:n)/365))
# [1] 0.000000000 0.009768138 0.013814233 0.016918911 0.019536276
# [6] 0.021842220 0.023926954 0.025844064 0.027628466 0.029304414
# [11] 0.030889564
lower.bounds <- qnorm(1-probability,mean=mean*(0:n)/365,sd=sigma*sqrt((0:n)/365))
# [1] 0.000000000 -0.009768138 -0.013814233 -0.016918911 -0.019536276
# [6] -0.021842220 -0.023926954 -0.025844064 -0.027628466 -0.029304414
# [11] -0.030889564
upper.cone <- S*exp(upper.bounds)
# [1] 23.62000 23.85185 23.94856 24.02303 24.08598
# [6] 24.14159 24.19197 24.23839 24.28168 24.32241
# [11] 24.36100
lower.cone <- S*exp(lower.bounds)
# [1] 23.62000 23.39040 23.29595 23.22374 23.16303
# [6] 23.10968 23.06155 23.01738 22.97635 22.93787
# [11] 22.90154
foo <- ggplot(data=data.frame(date=index(pcef_ad),data=coredata(pcef_ad)),aes(x=index(pcef_ad),y=coredata(pcef_ad))) +
geom_line() +
geom_polygon(data=data.frame(date=c(today()+0:n,today()+n:0),data=c(lower.cone,rev(upper.cone))),mapping=aes(x=date,y=data),alpha=1, fill = "pink")
foo
EDIT 2
He probado el código con un "pronóstico" período de los 1000 días, sólo para ver. Y hay algo en el producido de los valores que no entiendo: ¿por Qué es el rango superior más ancha que la inferior rango ? Parece que la predicción se tiene en cuenta la tendencia al alza pero, ¿cómo ? Honestamente yo esperaba que el rango para ser simétricos con respecto al último precio observado. Yo esperaba que la línea azul y la línea verde que tienen la misma longitud, pero el verde es más grande ... ¿por qué ?