library(quantmod)
library(tseries)
library(forecast)
library(FinTS)
library(rugarch)
library(ggplot2)
library(tidyr)

1 Zomato (ETERNAL.NS)

1.1 Price and Returns

getSymbols("ETERNAL.NS", src = "yahoo", from = "2023-01-01", to = "2026-03-30")
## [1] "ETERNAL.NS"
zomato_price <- Ad(ETERNAL.NS)
colnames(zomato_price) <- "Price"

plot(zomato_price,
     main = "Zomato - Adjusted Closing Price",
     col  = "steelblue", lwd = 1.5,
     ylab = "Price (INR)", xlab = "Date")

zomato_returns <- diff(log(zomato_price))
zomato_returns <- na.omit(zomato_returns)

plot(zomato_returns,
     main = "Zomato - Daily Log Returns",
     col  = "darkred", lwd = 1,
     ylab = "Log Return", xlab = "Date")

1.2 Stationarity Test (ADF)

adf.test(zomato_returns)
## 
##  Augmented Dickey-Fuller Test
## 
## data:  zomato_returns
## Dickey-Fuller = -9.6216, Lag order = 9, p-value = 0.01
## alternative hypothesis: stationary

1.3 ACF and PACF

par(mfrow = c(1, 2))
acf(zomato_returns,  main = "ACF - Zomato",  lag.max = 30)
pacf(zomato_returns, main = "PACF - Zomato", lag.max = 30)

par(mfrow = c(1, 1))

1.4 ARIMA Model

zomato_arima <- auto.arima(zomato_returns,
                            seasonal      = FALSE,
                            stepwise      = FALSE,
                            approximation = FALSE)
summary(zomato_arima)
## Series: zomato_returns 
## ARIMA(1,0,1) with non-zero mean 
## 
## Coefficients:
##           ar1     ma1    mean
##       -0.9131  0.9525  0.0016
## s.e.   0.0674  0.0521  0.0009
## 
## sigma^2 = 0.0005955:  log likelihood = 1756.45
## AIC=-3504.9   AICc=-3504.85   BIC=-3486.35
## 
## Training set error measures:
##                        ME       RMSE        MAE MPE MAPE     MASE        ACF1
## Training set 1.421569e-05 0.02435502 0.01850837 NaN  Inf 0.703212 0.001583951

1.5 Residual Diagnostics

checkresiduals(zomato_arima)

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(1,0,1) with non-zero mean
## Q* = 5.1901, df = 8, p-value = 0.7371
## 
## Model df: 2.   Total lags used: 10
Box.test(residuals(zomato_arima), lag = 10, type = "Ljung-Box")
## 
##  Box-Ljung test
## 
## data:  residuals(zomato_arima)
## X-squared = 5.1901, df = 10, p-value = 0.8781

1.6 ARCH Test

ArchTest(residuals(zomato_arima), lags = 10)
## 
##  ARCH LM-test; Null hypothesis: no ARCH effects
## 
## data:  residuals(zomato_arima)
## Chi-squared = 24.119, df = 10, p-value = 0.007292

1.7 GARCH(1,1) Model

garch_spec <- ugarchspec(
  variance.model     = list(model = "sGARCH", garchOrder = c(1, 1)),
  mean.model         = list(armaOrder = c(0, 0), include.mean = TRUE),
  distribution.model = "norm"
)
zomato_garch <- ugarchfit(spec = garch_spec, data = zomato_returns)
show(zomato_garch)
## 
## *---------------------------------*
## *          GARCH Model Fit        *
## *---------------------------------*
## 
## Conditional Variance Dynamics    
## -----------------------------------
## GARCH Model  : sGARCH(1,1)
## Mean Model   : ARFIMA(0,0,0)
## Distribution : norm 
## 
## Optimal Parameters
## ------------------------------------
##         Estimate  Std. Error  t value Pr(>|t|)
## mu      0.001542    0.000870   1.7731 0.076216
## omega   0.000102    0.000045   2.2662 0.023436
## alpha1  0.090322    0.037959   2.3794 0.017339
## beta1   0.742401    0.093777   7.9167 0.000000
## 
## Robust Standard Errors:
##         Estimate  Std. Error  t value Pr(>|t|)
## mu      0.001542    0.000849   1.8171 0.069208
## omega   0.000102    0.000065   1.5651 0.117552
## alpha1  0.090322    0.050098   1.8029 0.071406
## beta1   0.742401    0.128150   5.7932 0.000000
## 
## LogLikelihood : 1759.825 
## 
## Information Criteria
## ------------------------------------
##                     
## Akaike       -4.5904
## Bayes        -4.5661
## Shibata      -4.5904
## Hannan-Quinn -4.5811
## 
## Weighted Ljung-Box Test on Standardized Residuals
## ------------------------------------
##                         statistic p-value
## Lag[1]                     0.9782  0.3226
## Lag[2*(p+q)+(p+q)-1][2]    1.7146  0.3149
## Lag[4*(p+q)+(p+q)-1][5]    2.2306  0.5650
## d.o.f=0
## H0 : No serial correlation
## 
## Weighted Ljung-Box Test on Standardized Squared Residuals
## ------------------------------------
##                         statistic p-value
## Lag[1]                    0.03128  0.8596
## Lag[2*(p+q)+(p+q)-1][5]   0.34279  0.9790
## Lag[4*(p+q)+(p+q)-1][9]   3.71201  0.6380
## d.o.f=2
## 
## Weighted ARCH LM Tests
## ------------------------------------
##             Statistic Shape Scale P-Value
## ARCH Lag[3]   0.02311 0.500 2.000  0.8792
## ARCH Lag[5]   0.32152 1.440 1.667  0.9345
## ARCH Lag[7]   3.91296 2.315 1.543  0.3593
## 
## Nyblom stability test
## ------------------------------------
## Joint Statistic:  1.5836
## Individual Statistics:              
## mu     0.36528
## omega  0.29991
## alpha1 0.03869
## beta1  0.20019
## 
## Asymptotic Critical Values (10% 5% 1%)
## Joint Statistic:          1.07 1.24 1.6
## Individual Statistic:     0.35 0.47 0.75
## 
## Sign Bias Test
## ------------------------------------
##                    t-value   prob sig
## Sign Bias           0.5990 0.5494    
## Negative Sign Bias  0.1018 0.9190    
## Positive Sign Bias  0.6730 0.5012    
## Joint Effect        2.8861 0.4095    
## 
## 
## Adjusted Pearson Goodness-of-Fit Test:
## ------------------------------------
##   group statistic p-value(g-1)
## 1    20     32.20      0.02965
## 2    30     41.63      0.06064
## 3    40     49.27      0.12537
## 4    50     52.97      0.32347
## 
## 
## Elapsed time : 0.06669593

1.8 Volatility Decay

alpha1      <- coef(zomato_garch)["alpha1"]
beta1       <- coef(zomato_garch)["beta1"]
persistence <- alpha1 + beta1
decay       <- 1 - persistence
half_life   <- log(0.5) / log(persistence)

cat("Alpha1       :", round(alpha1, 4), "\n")
## Alpha1       : 0.0903
cat("Beta1        :", round(beta1, 4), "\n")
## Beta1        : 0.7424
cat("Persistence  :", round(persistence, 4), "\n")
## Persistence  : 0.8327
cat("Decay Rate   :", round(decay, 4), "\n")
## Decay Rate   : 0.1673
cat("Half-Life    :", round(half_life, 2), "days\n")
## Half-Life    : 3.79 days
decay_df <- data.frame(Day = 1:60, Persistence = persistence^(1:60))

ggplot(decay_df, aes(x = Day, y = Persistence)) +
  geom_line(color = "red", linewidth = 1.2) +
  geom_hline(yintercept = 0.5, linetype = "dashed", color = "gray40") +
  geom_vline(xintercept = half_life, linetype = "dotted", color = "steelblue") +
  labs(title    = "Zomato - GARCH Volatility Decay Curve",
       subtitle = paste("Half-life =", round(half_life, 2), "trading days"),
       x = "Days After Shock", y = "Proportion of Volatility Remaining") +
  theme_minimal()

1.9 30-Day Forecast

zomato_fc     <- forecast(zomato_arima, h = 30)
zomato_last   <- as.numeric(tail(zomato_price, 1))
zomato_prices <- zomato_last * exp(cumsum(as.numeric(zomato_fc$mean)))

zomato_dates <- seq(as.Date("2026-03-31"), by = "day", length.out = 45)
zomato_dates <- zomato_dates[!weekdays(zomato_dates) %in% c("Saturday", "Sunday")][1:30]

zomato_df <- data.frame(Date = zomato_dates, Price = zomato_prices)

ggplot(zomato_df, aes(x = Date, y = Price)) +
  geom_line(color = "steelblue", linewidth = 1.2) +
  geom_hline(yintercept = zomato_last, linetype = "dashed", color = "red") +
  labs(title    = "Zomato - 30 Day Price Forecast",
       subtitle = paste("Last Known Price: Rs.", round(zomato_last, 2)),
       x = "Date", y = "Forecasted Price (INR)") +
  theme_minimal()

garch_vf <- ugarchforecast(zomato_garch, n.ahead = 30)
vol_df   <- data.frame(Day = 1:30, Volatility = as.numeric(sigma(garch_vf)))

ggplot(vol_df, aes(x = Day, y = Volatility)) +
  geom_line(color = "darkred", linewidth = 1.2) +
  labs(title = "Zomato - 30 Day Volatility Forecast (GARCH)",
       x = "Days Ahead", y = "Expected Daily Volatility (Sigma)") +
  theme_minimal()


2 Nykaa (NYKAA.NS)

2.1 Price and Returns

getSymbols("NYKAA.NS", src = "yahoo", from = "2023-01-01", to = "2026-03-30")
## [1] "NYKAA.NS"
nykaa_price <- Ad(NYKAA.NS)
colnames(nykaa_price) <- "Price"

plot(nykaa_price,
     main = "Nykaa - Adjusted Closing Price",
     col  = "purple", lwd = 1.5,
     ylab = "Price (INR)", xlab = "Date")

nykaa_returns <- diff(log(nykaa_price))
nykaa_returns <- na.omit(nykaa_returns)

plot(nykaa_returns,
     main = "Nykaa - Daily Log Returns",
     col  = "darkorchid", lwd = 1,
     ylab = "Log Return", xlab = "Date")

2.2 Stationarity Test (ADF)

adf.test(nykaa_returns)
## 
##  Augmented Dickey-Fuller Test
## 
## data:  nykaa_returns
## Dickey-Fuller = -9.8727, Lag order = 9, p-value = 0.01
## alternative hypothesis: stationary

2.3 ACF and PACF

par(mfrow = c(1, 2))
acf(nykaa_returns,  main = "ACF - Nykaa",  lag.max = 30)
pacf(nykaa_returns, main = "PACF - Nykaa", lag.max = 30)

par(mfrow = c(1, 1))

2.4 ARIMA Model

nykaa_arima <- auto.arima(nykaa_returns,
                           seasonal      = FALSE,
                           stepwise      = FALSE,
                           approximation = FALSE)
summary(nykaa_arima)
## Series: nykaa_returns 
## ARIMA(0,0,5) with zero mean 
## 
## Coefficients:
##          ma1      ma2     ma3      ma4      ma5
##       0.0367  -0.0111  0.0380  -0.0342  -0.1324
## s.e.  0.0351   0.0351  0.0353   0.0353   0.0357
## 
## sigma^2 = 0.0004126:  log likelihood = 1979.53
## AIC=-3947.07   AICc=-3946.96   BIC=-3918.97
## 
## Training set error measures:
##                        ME       RMSE       MAE MPE MAPE      MASE         ACF1
## Training set 0.0006083864 0.02024964 0.0148479 NaN  Inf 0.6991005 0.0004389825

2.5 Residual Diagnostics

checkresiduals(nykaa_arima)

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(0,0,5) with zero mean
## Q* = 0.60782, df = 5, p-value = 0.9876
## 
## Model df: 5.   Total lags used: 10
Box.test(residuals(nykaa_arima), lag = 10, type = "Ljung-Box")
## 
##  Box-Ljung test
## 
## data:  residuals(nykaa_arima)
## X-squared = 0.60782, df = 10, p-value = 1

2.6 ARCH Test

ArchTest(residuals(nykaa_arima), lags = 10)
## 
##  ARCH LM-test; Null hypothesis: no ARCH effects
## 
## data:  residuals(nykaa_arima)
## Chi-squared = 10.197, df = 10, p-value = 0.4234

2.7 30-Day Forecast

nykaa_fc     <- forecast(nykaa_arima, h = 30)
nykaa_last   <- as.numeric(tail(nykaa_price, 1))
nykaa_prices <- nykaa_last * exp(cumsum(as.numeric(nykaa_fc$mean)))

nykaa_dates <- seq(as.Date("2026-03-31"), by = "day", length.out = 45)
nykaa_dates <- nykaa_dates[!weekdays(nykaa_dates) %in% c("Saturday", "Sunday")][1:30]

nykaa_df <- data.frame(Date = nykaa_dates, Price = nykaa_prices)

ggplot(nykaa_df, aes(x = Date, y = Price)) +
  geom_line(color = "purple", linewidth = 1.2) +
  geom_hline(yintercept = nykaa_last, linetype = "dashed", color = "red") +
  labs(title    = "Nykaa - 30 Day Price Forecast",
       subtitle = paste("Last Known Price: Rs.", round(nykaa_last, 2)),
       x = "Date", y = "Forecasted Price (INR)") +
  theme_minimal()


3 Delhivery (DELHIVERY.NS)

3.1 Price and Returns

getSymbols("DELHIVERY.NS", src = "yahoo", from = "2023-01-01", to = "2026-03-30")
## [1] "DELHIVERY.NS"
delhivery_price <- Ad(DELHIVERY.NS)
colnames(delhivery_price) <- "Price"

plot(delhivery_price,
     main = "Delhivery - Adjusted Closing Price",
     col  = "darkorange", lwd = 1.5,
     ylab = "Price (INR)", xlab = "Date")

delhivery_returns <- diff(log(delhivery_price))
delhivery_returns <- na.omit(delhivery_returns)

plot(delhivery_returns,
     main = "Delhivery - Daily Log Returns",
     col  = "orange3", lwd = 1,
     ylab = "Log Return", xlab = "Date")

3.2 Stationarity Test (ADF)

adf.test(delhivery_returns)
## 
##  Augmented Dickey-Fuller Test
## 
## data:  delhivery_returns
## Dickey-Fuller = -9.1249, Lag order = 9, p-value = 0.01
## alternative hypothesis: stationary

3.3 ACF and PACF

par(mfrow = c(1, 2))
acf(delhivery_returns,  main = "ACF - Delhivery",  lag.max = 30)
pacf(delhivery_returns, main = "PACF - Delhivery", lag.max = 30)

par(mfrow = c(1, 1))

3.4 ARIMA Model

delhivery_arima <- auto.arima(delhivery_returns,
                               seasonal      = FALSE,
                               stepwise      = FALSE,
                               approximation = FALSE)
summary(delhivery_arima)
## Series: delhivery_returns 
## ARIMA(0,0,0) with zero mean 
## 
## sigma^2 = 0.0004472:  log likelihood = 1945
## AIC=-3888   AICc=-3887.99   BIC=-3883.31
## 
## Training set error measures:
##                        ME       RMSE        MAE MPE MAPE      MASE        ACF1
## Training set 0.0003208525 0.02114652 0.01530683 100  100 0.6975244 -0.02960336

3.5 Residual Diagnostics

checkresiduals(delhivery_arima)

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(0,0,0) with zero mean
## Q* = 11.603, df = 10, p-value = 0.3125
## 
## Model df: 0.   Total lags used: 10
Box.test(residuals(delhivery_arima), lag = 10, type = "Ljung-Box")
## 
##  Box-Ljung test
## 
## data:  residuals(delhivery_arima)
## X-squared = 11.603, df = 10, p-value = 0.3125

3.6 ARCH Test

ArchTest(residuals(delhivery_arima), lags = 10)
## 
##  ARCH LM-test; Null hypothesis: no ARCH effects
## 
## data:  residuals(delhivery_arima)
## Chi-squared = 14.357, df = 10, p-value = 0.1573

3.7 30-Day Forecast

delhivery_fc     <- forecast(delhivery_arima, h = 30)
delhivery_last   <- as.numeric(tail(delhivery_price, 1))
delhivery_prices <- delhivery_last * exp(cumsum(as.numeric(delhivery_fc$mean)))

delhivery_dates <- seq(as.Date("2026-03-31"), by = "day", length.out = 45)
delhivery_dates <- delhivery_dates[!weekdays(delhivery_dates) %in% c("Saturday", "Sunday")][1:30]

delhivery_df <- data.frame(Date = delhivery_dates, Price = delhivery_prices)

ggplot(delhivery_df, aes(x = Date, y = Price)) +
  geom_line(color = "darkorange", linewidth = 1.2) +
  geom_hline(yintercept = delhivery_last, linetype = "dashed", color = "red") +
  labs(title    = "Delhivery - 30 Day Price Forecast",
       subtitle = paste("Last Known Price: Rs.", round(delhivery_last, 2)),
       x = "Date", y = "Forecasted Price (INR)") +
  theme_minimal()


4 Naukri / Info Edge (NAUKRI.NS)

4.1 Price and Returns

getSymbols("NAUKRI.NS", src = "yahoo", from = "2023-01-01", to = "2026-03-30")
## [1] "NAUKRI.NS"
naukri_price <- Ad(NAUKRI.NS)
colnames(naukri_price) <- "Price"

plot(naukri_price,
     main = "Naukri - Adjusted Closing Price",
     col  = "darkgreen", lwd = 1.5,
     ylab = "Price (INR)", xlab = "Date")

naukri_returns <- diff(log(naukri_price))
naukri_returns <- na.omit(naukri_returns)

plot(naukri_returns,
     main = "Naukri - Daily Log Returns",
     col  = "forestgreen", lwd = 1,
     ylab = "Log Return", xlab = "Date")

4.2 Stationarity Test (ADF)

adf.test(naukri_returns)
## 
##  Augmented Dickey-Fuller Test
## 
## data:  naukri_returns
## Dickey-Fuller = -10.054, Lag order = 9, p-value = 0.01
## alternative hypothesis: stationary

4.3 ACF and PACF

par(mfrow = c(1, 2))
acf(naukri_returns,  main = "ACF - Naukri",  lag.max = 30)
pacf(naukri_returns, main = "PACF - Naukri", lag.max = 30)

par(mfrow = c(1, 1))

4.4 ARIMA Model

naukri_arima <- auto.arima(naukri_returns,
                            seasonal      = FALSE,
                            stepwise      = FALSE,
                            approximation = FALSE)
summary(naukri_arima)
## Series: naukri_returns 
## ARIMA(3,0,0) with zero mean 
## 
## Coefficients:
##          ar1      ar2     ar3
##       0.0077  -0.1020  0.0642
## s.e.  0.0353   0.0351  0.0354
## 
## sigma^2 = 0.0003648:  log likelihood = 2027.78
## AIC=-4047.55   AICc=-4047.5   BIC=-4028.82
## 
## Training set error measures:
##                        ME      RMSE       MAE MPE MAPE      MASE        ACF1
## Training set 0.0003244283 0.0190625 0.0142931 NaN  Inf 0.6876491 0.000722082

4.5 Residual Diagnostics

checkresiduals(naukri_arima)

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(3,0,0) with zero mean
## Q* = 5.4279, df = 7, p-value = 0.6079
## 
## Model df: 3.   Total lags used: 10
Box.test(residuals(naukri_arima), lag = 10, type = "Ljung-Box")
## 
##  Box-Ljung test
## 
## data:  residuals(naukri_arima)
## X-squared = 5.4279, df = 10, p-value = 0.8608

4.6 ARCH Test

ArchTest(residuals(naukri_arima), lags = 10)
## 
##  ARCH LM-test; Null hypothesis: no ARCH effects
## 
## data:  residuals(naukri_arima)
## Chi-squared = 8.6926, df = 10, p-value = 0.5615

4.7 30-Day Forecast

naukri_fc     <- forecast(naukri_arima, h = 30)
naukri_last   <- as.numeric(tail(naukri_price, 1))
naukri_prices <- naukri_last * exp(cumsum(as.numeric(naukri_fc$mean)))

naukri_dates <- seq(as.Date("2026-03-31"), by = "day", length.out = 45)
naukri_dates <- naukri_dates[!weekdays(naukri_dates) %in% c("Saturday", "Sunday")][1:30]

naukri_df <- data.frame(Date = naukri_dates, Price = naukri_prices)

ggplot(naukri_df, aes(x = Date, y = Price)) +
  geom_line(color = "darkgreen", linewidth = 1.2) +
  geom_hline(yintercept = naukri_last, linetype = "dashed", color = "red") +
  labs(title    = "Naukri - 30 Day Price Forecast",
       subtitle = paste("Last Known Price: Rs.", round(naukri_last, 2)),
       x = "Date", y = "Forecasted Price (INR)") +
  theme_minimal()


5 IndiaMART (INDIAMART.NS)

5.1 Price and Returns

getSymbols("INDIAMART.NS", src = "yahoo", from = "2023-01-01", to = "2026-03-30")
## [1] "INDIAMART.NS"
indiamart_price <- Ad(INDIAMART.NS)
colnames(indiamart_price) <- "Price"

plot(indiamart_price,
     main = "IndiaMART - Adjusted Closing Price",
     col  = "royalblue", lwd = 1.5,
     ylab = "Price (INR)", xlab = "Date")

indiamart_returns <- diff(log(indiamart_price))
indiamart_returns <- na.omit(indiamart_returns)

plot(indiamart_returns,
     main = "IndiaMART - Daily Log Returns",
     col  = "blue3", lwd = 1,
     ylab = "Log Return", xlab = "Date")

5.2 Stationarity Test (ADF)

adf.test(indiamart_returns)
## 
##  Augmented Dickey-Fuller Test
## 
## data:  indiamart_returns
## Dickey-Fuller = -10.103, Lag order = 9, p-value = 0.01
## alternative hypothesis: stationary

5.3 ACF and PACF

par(mfrow = c(1, 2))
acf(indiamart_returns,  main = "ACF - IndiaMART",  lag.max = 30)
pacf(indiamart_returns, main = "PACF - IndiaMART", lag.max = 30)

par(mfrow = c(1, 1))

5.4 ARIMA Model

indiamart_arima <- auto.arima(indiamart_returns,
                               seasonal      = FALSE,
                               stepwise      = FALSE,
                               approximation = FALSE)
summary(indiamart_arima)
## Series: indiamart_returns 
## ARIMA(0,0,0) with zero mean 
## 
## sigma^2 = 0.0003617:  log likelihood = 2029.59
## AIC=-4057.18   AICc=-4057.18   BIC=-4052.5
## 
## Training set error measures:
##                         ME       RMSE        MAE MPE MAPE      MASE        ACF1
## Training set -7.698239e-05 0.01901958 0.01301462 100  100 0.6926321 -0.03157466

5.5 Residual Diagnostics

checkresiduals(indiamart_arima)

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(0,0,0) with zero mean
## Q* = 11.735, df = 10, p-value = 0.3032
## 
## Model df: 0.   Total lags used: 10
Box.test(residuals(indiamart_arima), lag = 10, type = "Ljung-Box")
## 
##  Box-Ljung test
## 
## data:  residuals(indiamart_arima)
## X-squared = 11.735, df = 10, p-value = 0.3032

5.6 ARCH Test

ArchTest(residuals(indiamart_arima), lags = 10)
## 
##  ARCH LM-test; Null hypothesis: no ARCH effects
## 
## data:  residuals(indiamart_arima)
## Chi-squared = 6.22, df = 10, p-value = 0.7965

5.7 30-Day Forecast

indiamart_fc     <- forecast(indiamart_arima, h = 30)
indiamart_last   <- as.numeric(tail(indiamart_price, 1))
indiamart_prices <- indiamart_last * exp(cumsum(as.numeric(indiamart_fc$mean)))

indiamart_dates <- seq(as.Date("2026-03-31"), by = "day", length.out = 45)
indiamart_dates <- indiamart_dates[!weekdays(indiamart_dates) %in% c("Saturday", "Sunday")][1:30]

indiamart_df <- data.frame(Date = indiamart_dates, Price = indiamart_prices)

ggplot(indiamart_df, aes(x = Date, y = Price)) +
  geom_line(color = "royalblue", linewidth = 1.2) +
  geom_hline(yintercept = indiamart_last, linetype = "dashed", color = "red") +
  labs(title    = "IndiaMART - 30 Day Price Forecast",
       subtitle = paste("Last Known Price: Rs.", round(indiamart_last, 2)),
       x = "Date", y = "Forecasted Price (INR)") +
  theme_minimal()


6 All 5 Stocks - Indexed Comparison

all_forecasts <- data.frame(
  Date      = zomato_dates,
  Zomato    = zomato_prices,
  Nykaa     = nykaa_prices,
  Delhivery = delhivery_prices,
  Naukri    = naukri_prices,
  IndiaMART = indiamart_prices
)

all_norm <- all_forecasts
all_norm$Zomato    <- 100 * all_norm$Zomato    / all_norm$Zomato[1]
all_norm$Nykaa     <- 100 * all_norm$Nykaa     / all_norm$Nykaa[1]
all_norm$Delhivery <- 100 * all_norm$Delhivery / all_norm$Delhivery[1]
all_norm$Naukri    <- 100 * all_norm$Naukri    / all_norm$Naukri[1]
all_norm$IndiaMART <- 100 * all_norm$IndiaMART / all_norm$IndiaMART[1]

all_long <- pivot_longer(all_norm, cols = -Date,
                         names_to  = "Stock",
                         values_to = "IndexedPrice")

ggplot(all_long, aes(x = Date, y = IndexedPrice, color = Stock)) +
  geom_line(linewidth = 1.1) +
  geom_hline(yintercept = 100, linetype = "dashed", color = "gray50") +
  labs(title    = "30-Day Forecast - All 5 Stocks (Indexed to 100)",
       subtitle = "Base = First Forecast Day | April-May 2026",
       x = "Date", y = "Indexed Price", color = "Stock") +
  theme_minimal()