Machine Learning Insights on BIST 100’s Future

The BIST100 was rising before the Turkish Central Bank’s rate cuts; could that be an initial signal of a firm uptrend? The ML model tells us there is much more room to go up.

library(tidyverse)
library(tidymodels)
library(tidyquant)
library(timetk)
library(modeltime)

#BIST 100 (XU100.IS)
df_bist <- 
  tq_get("XU100.IS") %>% 
  mutate(date = as.Date(date),
         year_month = tsibble::yearmonth(date)) %>% 
  group_by(year_month) %>%                         
  filter(day(date) <= 5) %>%                      
  slice_max(date) %>% 
  ungroup() %>% 
  mutate(date = floor_date(date, "month")) %>% 
  select(date, bist = close) %>% 
  drop_na() %>% 
  filter(date >= as.Date("2020-08-01"))

df_bist <- 
  tq_get("XU100.IS") %>% 
  filter(date >= as.Date("2022-03-05")) %>% 
  select(date, bist = close) %>% 
  drop_na()



#Splitting tha data
df_split <- 
  df_bist %>% 
  time_series_split(assess = "6 months",
                    cumulative = TRUE)

df_train <- training(df_split)
df_test <- testing(df_split)

#Auto ARIMA
model_fit_arima_reg <- 
  arima_reg() %>%
  set_engine(engine = "auto_arima") %>%
  fit(bist ~ date, data = df_train)

#Boosted ARIMA
model_fit_arima_boosted <- 
  arima_boost(
    min_n = 2,
    learn_rate = 0.015
  ) %>%
  set_engine(engine = "auto_arima_xgboost") %>%
  fit(bist ~ date + as.numeric(date) + factor(week(date), ordered = F),
      data = df_train)

#Exponential Smoothing
model_fit_ets <- 
  exp_smoothing() %>%
  set_engine(engine = "ets") %>%
  fit(bist ~ date, data = df_train)

#Prophet
model_fit_prophet <- 
  prophet_reg() %>%
  set_engine(engine = "prophet") %>%
  fit(bist ~ date, data = df_train)

#Linear Regression
model_fit_lm <- 
  linear_reg() %>%
  set_engine("lm") %>%
  fit(bist ~ as.numeric(date) + factor(week(date), ordered = FALSE),
      data = df_train)


#MARS
model_spec_mars <- 
  mars(mode = "regression") %>%
  set_engine("earth") 

recipe_spec <- 
  recipe(bist ~ date, data = df_train) %>%
  step_date(date, features = "week", ordinal = FALSE) %>%
  step_mutate(date_num = as.numeric(date)) %>%
  step_normalize(date_num) %>%
  step_rm(date)

wflw_fit_mars <- 
  workflow() %>%
  add_recipe(recipe_spec) %>%
  add_model(model_spec_mars) %>%
  fit(df_train)

#Add fitted models to a Model Table
models_tbl <- 
  modeltime_table(
    model_fit_arima_reg,
    model_fit_arima_boosted,
    model_fit_ets,
    model_fit_prophet,
    model_fit_lm,
    wflw_fit_mars
  )

#Calibrate the model to a testing set
calibration_tbl <- 
  models_tbl %>%
  modeltime_calibrate(new_data = df_test)

#Accuracy
calibration_tbl %>%
  modeltime_accuracy() %>%
  table_modeltime_accuracy(
    .interactive = FALSE
  )

#Calibrate the Linear Regression model to a testing set
calibration_lm <- 
  model_fit_lm %>%
  modeltime_calibrate(new_data = df_test)


#Predictive intervals (95% Confidence Interval)
calibration_lm %>%
  modeltime_forecast(actual_data = df_bist %>% 
                       filter(date >= last(date) - months(6)),
                     new_data = df_test) %>%
  plot_modeltime_forecast(.interactive = FALSE,
                          .legend_show = FALSE,
                          .line_size = 1.5,
                          .color_lab = "",
                          .title = "BIST 100") +
  geom_point(aes(color = .key)) +
  labs(subtitle = "<span style = 'color:turquoise;'>Monthly Index</span><br><span style = 'color:dimgrey;'>Predictive Intervals</span><br><span style = 'color:red;'>ML Model</span>") + 
  scale_x_date(breaks = seq(make_date(2024,9,1),
                            make_date(2025,3,1),
                            by = "month"),
               labels = scales::label_date(format = "%b'%y"),
               expand = expansion(mult = c(.1, .1))) +
  scale_y_continuous(labels = scales::label_currency(prefix = "",
                                                     suffix = "₺")) +
  theme_minimal(base_family = "Roboto Slab", base_size = 20) +
  theme(legend.position = "none",
        plot.background = element_rect(fill = "azure", 
                                       color = "azure"),
        plot.title = element_text(face = "bold"),
        axis.text = element_text(face = "bold"),
        axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1),
        plot.subtitle = ggtext::element_markdown(face = "bold"))

One response to “Machine Learning Insights on BIST 100’s Future”

  1. bitfool Avatar
    bitfool

    I am unsure about the reason for the error I am getting trying to run this. Console (in R Studio) output:

    >source(“~/.active-rstudio-document”)
    Using date_var: date
    frequency = 5 observations per 1 week
    frequency = 5 observations per 1 week
    frequency = 5 observations per 1 week
    Disabling daily seasonality. Run prophet with daily.seasonality=TRUE to override this.
    ℹ We have detected a possible intermittent series, you can change the default metric set to the extended_forecast_accuracy_metric_set() containing the MAAPE metric, which is more appropriate for this type of series.
    Error: Problem occurred during prediction. Error in model.frame.default(Terms,
    newdata, na.action = na.action, xlev = object$xlevels): factor
    factor(week(date), ordered = FALSE) has new levels 53

    Any thoughts on how to correct this problem?

    Like

Leave a reply to bitfool Cancel reply

I’m Selcuk Disci

The DataGeeek focuses on machine learning, deep learning, and Generative AI in data science using financial data for educational and informational purposes.

Let’s connect