Абстрактный

Существует несколько способов прогнозирования цен на акции. Многие методы, от слепого угадывания до машинного обучения, были протестированы для достижения достойных результатов. Учет сложности рынка в модели — сложная задача, но ее можно разбить на несколько подходов.

Поскольку предсказать точное процентное увеличение акций на следующий день сложно, вместо этого мы можем попытаться предсказать направление движения. В качестве альтернативы мы можем посмотреть на тренды и сезонность данных и попытаться предсказать с некоторой степенью уверенности, где будет цена через произвольное количество дней.

Логистические модели, пытающиеся предсказать направление движения на следующий день, дали плохие результаты. Вряд ли какая-либо предикторная переменная была значимой, а точность классификации составляла около 52%, что вряд ли лучше, чем угадывание. Панельная регрессия, а также авторегрессионные модели, использующие ARIMA, пытаются предсказать цены закрытия акций, используя одну акцию за раз. Панельная регрессия пытается построить одну модель для любого количества акций за одни и те же периоды времени. Это также дало плохие и спорадические результаты при прогнозировании по акциям. С другой стороны, авторегрессионные модели, которые предсказывают последующие значения временного ряда акций, оказались более полезными. Это потребовало найти подходящую комбинацию параметров, чтобы точно соответствовать данным. Ключевые слова

  1. Временная последовательность
  2. Логистическая регрессия
  3. Авторегрессионные модели
  4. Панельная регрессия

Введение

Поиск надежных способов прогнозирования цен на акции является сложной задачей, и используемые методы часто дают неудовлетворительные результаты. Многие данные фондового рынка легко доступны, и важно найти значимые переменные-предикторы среди всех вариантов. Если мы считаем, что цену акции или направление ее движения можно предсказать, используя недавнюю информацию, то мы можем посмотреть на переменные, связанные с недавними движениями, с такими индикаторами, как RSI или скользящие средние, а также внутридневные колебания цены с помощью OHLC. Цены.

Если, с другой стороны, мы считаем, что тренды и долгосрочные движения являются лучшим способом прогнозирования цен, тогда можно использовать анализ временных рядов. Анализ состоит в сравнении ряда цен, таких как цена закрытия акции, с ее запаздывающей или смещенной версией, чтобы выявить любые временные корреляции. Этот метод требует выполнения определенных допущений, которые требуют преобразования данных. С помощью различных подходов к моделированию и настройки параметров мы можем предсказать будущие цены с определенной степенью достоверности.

Вы можете найти весь код на R на моем github:

https://github.com/ilyashaikal02/StockPredictions

Эксперименты и результаты

Описание данных

Описание переменных следующее:

dataset <- read_csv('stocks_combined.csv')
tickers <- read_csv('tickers.csv')

Тикеры, доступные в этом наборе данных, перечислены ниже. Мы сосредоточимся на акциях AAPL, которые описаны ниже.

tickers

Обработка данных

Единственная необходимая обработка данных — это правильное форматирование столбца даты.

dataset$date <- as.Date(dataset$date, format="%m/%d/%Y")

Разработка функций

Набор данных дополнен техническими индикаторами из пакета ta-lib и создана целевая переменная для логистической модели. Наблюдения необходимо отбрасывать там, где вводятся значения NA из-за смещения, требуемого оконными функциями. Нас интересуют скорости изменения, а не стоимость, чтобы иметь возможность покупать любые акции, которые не будут иметь одинаковую цену.

  • TARGET: целевая переменная binaby для логистической модели.
  • MACD: сигнал MACD (только) с типичными размерами окна 12 и 26.
  • m5: индикатор импульса за последние 5 дней (скользящее среднее за одну торговую неделю).
  • m20: индикатор импульса за последние 20 дней (скользящее среднее за один торговый месяц).
  • vol1: скорость изменения громкости за последний день.
  • vol5: скорость изменения объема за последние пять дней (одна торговая неделя).
AAPL <- dataset %>% filter(ticker=='AAPL') 

# Augment data frame
AAPL_full <- AAPL %>% mutate(macd=MACD(Cl(AAPL), nFast=12, nSlow=26, nSig=9, maType=SMA)[,1], 
                        m5=momentum(AAPL$close, n=5), 
                        m20=momentum(AAPL$close, n=20), 
                        rsi=RSI(AAPL$close, n=14),
                        vol1=ROC(AAPL$volume, n=1),
                        vol5=ROC(AAPL$volume, n=5)) %>%
                        drop_na() %>%
                      select(-c(date,ticker,label, changeOverTime))

# Create target variable
AAPL_model1_data <- AAPL_full%>% 
                  mutate(TARGET=if_else(shift(close, n=1, fill=NA, type="lead") > close, 1, 0)) %>%
                  #select(-c(date,ticker,label,open,high,low,close,volume,unadjustedVolume,vwap,change,changeOverTime)) %>%
                  drop_na()
                  
AAPL_model1_data$TARGET <- factor(AAPL_model1_data$TARGET)

Исследование данных

Цена акций AAPL с годами неуклонно росла. Есть два важных периода снижения, но общая тенденция остается положительной. Эти периоды снижения должны обеспечить баланс набора данных.

AAPL %>% ggplot(aes(x=date,y=close)) + geom_line() + ggtitle('AAPL Close Price')

Распределения переменных-предикторов в основном центрированы. Переменные, связанные с объемом, смещены в правый хвост. Переменные близкие, высокие и низкие

AAPL_full %>% 
  keep(is.numeric) %>%
  gather() %>% 
  ggplot(aes(x= value)) + 
  geom_histogram(fill='red') + 
  facet_wrap(~key, scales = 'free')

График корреляции показывает, что некоторые переменные почти полностью коррелированы. Это имеет смысл, учитывая, что некоторые из этих переменных обычно движутся вместе или являются производными от других.

library(corrplot)
corr_dataframe <- AAPL_model1_data %>% mutate_if(is.factor, as.numeric)
corr.d <- cor(corr_dataframe)
corr.d[ lower.tri( corr.d, diag = TRUE ) ] <- NA
corrplot( corr.d, type = "upper", diag = FALSE )

Целевая переменная, которую мы создали, имеет еще несколько наблюдений, в которых движение было положительным. Это кажется разумным.

AAPL_model1_data %>% ggplot(aes(x=TARGET)) + geom_histogram(stat="count")

Моделирование

Модель 1 (логистика)

# Initialize a df that will store the metrics of models
models.df <- tibble(id=character(), formula=character(), res.deviance=numeric(), null.deviance=numeric(),
                 aic=numeric(), accuracy=numeric(), sensitivity=numeric(), specificity=numeric(),
                precision.deviance=numeric(), stringsAsFactors=FALSE)
```{r include=FALSE}
# A function to extract the relevant metrics from the summary and confusion matrix
build_model <- function(id, formula, data) {
  glm.fit <- glm(formula, data=data, family=binomial(link="logit"))
  print(summary(glm.fit))
  glm.probs <- predict(glm.fit, type="response")
  # Confirm the 0.5 threshold
  glm.pred <- ifelse(glm.probs > 0.5, 1, 0)
  results <- tibble(target=data$TARGET, pred=glm.pred)
  results <- results %>%
    mutate(pred.class = as.factor(pred), target.class = as.factor(target))
  
  #print(confusionMatrix(results$pred.class,results$target.class, positive = "1"))
  
  acc <- confusionMatrix(results$pred.class,results$target.class, positive = "1")$overall['Accuracy']
  sens <- confusionMatrix(results$pred.class,results$target.class, positive = "1")$byClass['Sensitivity']
  spec <- confusionMatrix(results$pred.class,results$target.class, positive = "1")$byClass['Specificity']
  prec <- confusionMatrix(results$pred.class,results$target.class, positive = "1")$byClass['Precision']
  res.deviance <- glm.fit$deviance
  null.deviance <- glm.fit$null.deviance  
  aic <- glm.fit$aic
  metrics <- list(res.deviance=res.deviance, null.deviance=null.deviance,aic=aic, accuracy=acc, sensitivity=sens, specificity=spec, precision=prec)
  metrics <- lapply(metrics, round, 3)
  
  #plot(roc(results$target.class,glm.probs), print.auc = TRUE)
  model.df <- tibble(id=id, res.deviance=metrics$res.deviance, null.deviance=metrics$null.deviance, 
                         aic=metrics$aic, accuracy=metrics$accuracy, sensitivity=metrics$sensitivity, specificity=metrics$specificity, precision=metrics$precision)
  model.list <- list(model=glm.fit, df_info=model.df)
  return(model.list)
}
```

Полная модель M1A

Первая логистическая модель дает неудовлетворительные результаты. Только переменная close имеет значение. Выявлено, что многие переменные являются мультиколлинеарными. Это имеет смысл, учитывая, что ряд переменных, связанных с ценой, обычно движутся вместе (закрытие, открытие, минимум, максимум), а некоторые являются производными от других переменных. Модель следует сокращать, удаляя наименее значимые предикторы, пока модель не станет значимой.

model.full <- build_model('model.full', "TARGET ~ .", data = AAPL_model1_data)
models.df <- rbind(models.df,model.full$df_info)
#summary(model.full)

Факторы инфляции дисперсии

Маленькая модель M1B

Сведение модели только к значимым предикторам приводит к бессмысленным результатам, когда две переменные компенсируют друг друга.

model.small <- build_model('model.small', "TARGET ~ .-vol5 -high -rsi -open -vol1-changePercent-low-macd-m20-volume-unadjustedVolume-m5-change", data = AAPL_model1_data)
models.df <- rbind(models.df,model.small$df_info)
summary(model.small)

Мультиколлинеарность M1C удалена

Эта модель удаляет множество предикторов (open, high, low, vwap, change, macd), но добавляет Close2Open и Open2Open, чтобы попытаться сохранить некоторую информацию из отброшенных переменных. Удаленные переменные были определены как слишком коррелированные, и мы сохранили только предикторы с коэффициентами инфляции дисперсии ниже допустимого порога, как показано ниже. К сожалению, эта модель также лишена значимости.

m1c_data <- AAPL_model1_data
m1c_data$Close2Open <- m1c_data$open - shift(m1c_data$close, n=1, fill=NA, type="lag")
m1c_data$Open2Open <- m1c_data$open - shift(m1c_data$open, n=1, fill=NA, type="lag")
m1c_data_trimmed <- m1c_data %>% select(-c(open,high,low,vwap,change,macd)) %>% drop_na()

model.m1c  <- build_model('model.m1c', "TARGET ~ .", data = m1c_data_trimmed )
models.df <- rbind(models.df,model.m1c$df_info)
summary(model.m1c)

Факторы инфляции дисперсии

Результаты логистической модели

Результаты логистических моделей показаны ниже. Точность тестирования в выборке довольно низкая и составляет 52%. Ни одна модель не имеет определенного преимущества, поэтому мы переходим к другим типам моделей. Это упражнение можно улучшить, используя данные по другим акциям, удалив все переменные, зависящие от акций. Кроме того, можно использовать больше целей, таких как направление движения цены за 5 дней или 20 дней.

Модель 2 (авторегрессионные модели)

В этом разделе мы опускаем все предикторы, кроме цены закрытия временного ряда. Мы используем только информацию, содержащую сам ряд, чтобы соответствовать модели и делать прогнозы. Цена акций AAPL имела основной тренд, но большие колебания. Нам нужно проверить, выполняются ли определенные условия, чтобы смоделировать этот временной ряд. Сначала мы смотрим на автокорреляцию ряда и видим, что ряд сильно коррелирует со своими предыдущими значениями со значительным отставанием. Мы также рассматриваем PACF, который удаляет варианты, объясненные более ранними задержками, поэтому мы получаем только релевантные функции.

Идентификация модели AR часто выполняется с использованием PACF, в то время как модели MA используют ACF. Порядок модели определяется количеством учитываемых значимых лагов. PACF предлагает модель AR(1), а линия регрессии времени t на время t-1 показывает близкое линейное соответствие и высокостатистический коэффициент приблизительно 1 для t-1. Для получения оценки используется несколько методов, но коэффициент постоянен. Однако медленно затухающая АКФ предполагает, что ряд не является стационарным и что для стабилизации среднего значения может потребоваться некоторая степень дифференциации.

par(mfrow=c(2,2))
acf(AAPL$close)
pacf(AAPL$close)

t <- AAPL$close[-1]
t_1 <- AAPL$close[-length(AAPL$close)]
m2.lm <- lm(t ~ t_1)

plot(t_1, t)
abline(m2.lm, col=3, lwd=2)

summary(m2.lm)

Мы используем обобщенный метод наименьших квадратов, чтобы получить больше информации о моде. Мы указываем структуру корреляции ошибок первого порядка. Отметим, что коэффициент estiamte снова равен 1, а AIC равен 5478. Это послужит сравнением более сложных моделей.

AAPL_close <- ts(AAPL$close)
m2.gls <- gls(AAPL_close ~ time(AAPL_close), correlation = corAR1(form=~1))
summary(m2.gls)

Мы проверяем обоснованность добавленной авторегрессионной структуры с помощью теста отношения правдоподобия. При очень малом значении p мы можем отвергнуть нулевую гипотезу о том, что добавленный член не нужен.

m2.gls.0 <- update(m2.gls, correlation=NULL)
anova(m2.gls, m2.gls.0) # AR(1) vs Uncorrelated errors

Подгонка модели AR (1) с использованием функции «ar» подтверждает коэффициент приблизительно равный 1 (0,997).

Мы можем просмотреть комплектацию моделей GLS и AR(1) бок о бок.

par(mfrow=c(1,2))
m2.gls_fitted <- AAPL_close - residuals(m2.gls)
plot(AAPL$close, type = "l", col = 4, lty = 1, main="GLS")
points(m2.gls_fitted, type = "l", col = 2, lty = 2)

plot(AAPL$close, type = "l", col = 4, lty = 1, main="AR(1)")
points(m2.ar1_fitted, type = "l", col = 2, lty = 2)

Ранее мы отмечали, что медленно затухающая структура АКФ свидетельствует о нестационарности ряда. Мы проверяем это утверждение с помощью приведенных ниже тестов Дики Фуллера. Нулевая гипотеза о том, что ряд не является стационарным, не отвергается для исходного ряда, но отвергается для раз дифференцированного ряда. Следовательно, исходный ряд не является стационарным и должен быть продифференцирован, чтобы стабилизировать среднее значение.

Тест Дики Фуллера на временных рядах:

adf.test(diff(AAPL$close, differences=1))

Тест Дики-Фуллера на дифференцированных временных рядах:

adf.test(diff(AAPL$close, differences=1))

АРИМА

Модели ARIMA позволяют комбинировать структуру AR, показанную выше, с условиями дифференцирования и скользящего среднего.

Здесь мы рассмотрим первые два дифференциала. Дифференциалы более высокого порядка имеют среднее значение 0, но дисперсия, кажется, увеличивается в последней части ряда.

Заказать 1 дифференциал

Дифференциал 1-го порядка демонстрирует наибольшую корреляцию в положении 0 и значительное отставание в положении 6, в то время как частичная АКФ демонстрирует периодическое поведение с несколькими значительными запаздываниями в положениях 7 и 8.

APPLdiff1 <- diff(AAPL$close, differences=1)
par(mfrow=c(2,2))
acf(APPLdiff1, lag.max=20)             
pacf(APPLdiff1, lag.max=20)
plot.ts(APPLdiff1)

Заказать 2 дифференциала

С другой стороны, дифференциал второго порядка имеет несколько значимых лагов в позициях 1 и 7, а частичная АКФ затухает и остается значимой до лага 6.

APPLdiff2 <- diff(AAPL$close, differences=2)
par(mfrow=c(2,2))
acf(APPLdiff2, lag.max=20)             
pacf(APPLdiff2, lag.max=20)
plot.ts(APPLdiff2)

Исходя из этих наблюдений, мы можем изучить следующие модели ARMA (авторегрессионное скользящее среднее), которые возможны для дифференцированных временных рядов:

  • Первый порядок ARIMA (7,1,0): AR (7) высокого порядка в авторегрессионной структуре.
  • ARIMA первого порядка (0,1,2): структура скользящей средней MA(1)
  • ARIMA(1,1,1) первого порядка: комбинация ARMA(1,1)
  • Второй порядок ARIMA (1,2,0): авторегрессионная структура AR (1)
  • Второй порядок ARIMA(0,2,1): структура скользящей средней MA(1)
  • Второй порядок ARIMA (6,2,0): авторегрессионная структура AR (6)
  • Второй порядок ARIMA(6,2,1): комбинация ARMA(6,1)
arimadf <- tibble(model=character(), coef=character(), loglik=numeric(), aic=numeric()) 

arimamodels <- function(p,d,q) {
  # A specification of the non-seasonal part of the ARIMA model: the three components (p, d, q) are the AR order, the degree of differencing, and the MA order. ARMA(p,q)
  arima.model <- arima(AAPL$close, order = c(p,d,q))
  arima.model_fitted <- AAPL$close - residuals(arima.model)
  df <- tibble(model=paste0(p,d,q), loglik=arima.model$loglik, aic=arima.model$aic)
  return.list <- list(model=arima.model,fitted=arima.model_fitted, df=df)
  return(return.list)
}

Результаты модели

Результаты моделей ARIMA, перечисленных выше, напечатаны здесь. Мы обнаружили, что модель с самым низким значением AIC является дифференциальной моделью AR(7) первого порядка со значением 5466. Однако это также сложная модель с 8 параметрами. Предпочтительна модель меньшего размера с незначительно уменьшенным AIC. Мы можем выбрать любую из оставшихся 3 моделей параметров. Мы выбираем модель MA(1) второго порядка в качестве лучшей модели.

# First order models
m710 <- arimamodels(p=7, d=1, q=0)
arimadf <- rbind(arimadf, m710$df)
m012 <- arimamodels(p=0, d=1, q=2)
arimadf <- rbind(arimadf, m012$df)
m111 <- arimamodels(p=1, d=1, q=1)
arimadf <- rbind(arimadf, m111$df)

# Second order models
m120 <- arimamodels(p=1, d=2, q=0)
arimadf <- rbind(arimadf, m120$df)
m021 <- arimamodels(0, 2, 1)
arimadf <- rbind(arimadf, m021$df)
m620 <- arimamodels(6, 2, 0)
arimadf <- rbind(arimadf, m620$df)
m621 <- arimamodels(6, 2, 1)
arimadf <- rbind(arimadf, m621$df)

arimadf

Коэффициенты для лучшей модели перечислены ниже, и мы также можем видеть из графика, что модель хорошо подходит.

m021$model

plot(AAPL$close, type = "l", col = 4, lty = 1)
points(m021$fitted, type = "l", col = 2, lty = 2)

Теперь мы можем использовать модель для прогнозирования цены акции. В приведенном ниже примере цена прогнозируется на следующие 150 торговых дней. Доверительные интервалы (показаны синим цветом) приведены для уровней 80% и 95%.

AAPLforecast <- forecast(m021$model, h=150)
autoplot(AAPLforecast)

Прогноз против факта

arimaforecast <- function(stock, ticker) {
  # Subset the training data, fit model and get fitted valyes
  training_subset <- stock$close[1:round(0.7*length(AAPL$close))] 
  model <- arima(training_subset, order = c(0, 2, 1))
  fitted_values <- training_subset - residuals(model)
  
  boundary <- round(length(stock$close)*.7)
  end <- length(stock$close)
  data <- tibble(date=stock$date, price=stock$close, prediction = NA, fitted=NA, Low95 = NA,
         Low80 = NA,
         High95 = NA,
         High80 = NA)
  stocksubsetforecast <- forecast(model, h=377)
  forecast_df <- fortify(as.data.frame(stocksubsetforecast)) %>% as_tibble()
  forecast_df <- forecast_df %>%
    rename("Low95" = "Lo 95",
           "Low80" = "Lo 80",
           "High95" = "Hi 95",
           "High80" = "Hi 80",
           "Forecast" = "Point Forecast")
  data$fitted <- c(as.vector(fitted_values),rep(NA,(end-boundary)))
  data$prediction <- c(rep(NA,boundary),forecast_df$Forecast)
  data$Low80 <- c(rep(NA,boundary),forecast_df$Low80)
  data$High80 <- c(rep(NA,boundary),forecast_df$High80)
  data$Low95 <- c(rep(NA,boundary),forecast_df$Low95)
  data$High95 <- c(rep(NA,boundary),forecast_df$High95)
  
  ggplot(data, aes(x = date)) + 
    geom_ribbon(aes(ymin = Low95, ymax = High95, fill = "95%")) +
    geom_ribbon(aes(ymin = Low80, ymax = High80, fill = "80%")) +
    geom_point(aes(y = price, colour = "price"), size = 1) +
    geom_line(aes(y = price, group = 1, colour = "price"), 
              linetype = "dotted", size = 0.75) +
    geom_line(aes(y = fitted, group = 2, colour = "fitted"), size = 0.75) +
    geom_line(aes(y = prediction, group = 3, colour = "prediction"), size = 0.75) +
    scale_x_date(breaks = scales::pretty_breaks(), date_labels = "%b %y") +
    scale_colour_brewer(name = "Legend", type = "qual", palette = "Dark2") +
    scale_fill_brewer(name = "Intervals") +
    guides(colour = guide_legend(order = 1), fill = guide_legend(order = 2)) +
    theme_bw(base_size = 14) +
    ggtitle(ticker)
}

Теперь, когда у нас есть подходящая модель, которая может предсказывать цену акции, мы можем сравнить эффективность прогнозирования с фактической ценой акции, подставив обучающую выборку, используя первые 70% данных и прогнозируя оставшиеся 30% данных. торговые дни. Мы обнаружили, что фактическая цена AAPL остается в пределах 80% и 95% лент доверительного интервала. Фактическая цена немного ниже, чем линейно предсказанная цена. Мы также проверили, как структура этой модели ARIMA обобщается на другие временные ряды цен на акции. Ниже приведены прогнозы цен для Microsoft и IBM. В случае первого цена остается в верхней части 95% доверительного интервала и даже превышает его. Окончательная цена намного выше прогноза. Прогноз для IBM больше в диапазоне линейного предиктора кажется разумной оценкой движения.

arimaforecast(AAPL,'AAPL')

MSFT <- dataset %>% filter(ticker=='MSFT') 
IBM <- dataset %>% filter(ticker=='IBM') 
arimaforecast(MSFT,'MSFT') # Microsoft Corporation

arimaforecast(IBM,'IBM') # International Business Machines Corporation

Модель 3 (панельная регрессия)

Для 3-й модели мы попытаемся представить модели в наборе данных об акциях, поскольку этот набор данных предоставляет данные по акциям и во времени, таким образом, имея как поперечное сечение, так и измерения временных рядов. Общее предположение для этого набора данных состоит в том, что существует временная корреляция для данной акции, но каждая акция не зависит от других акций. В этом наборе данных нет инвариантных во времени регрессоров.

Набор данных баланса

Определите, наблюдаются ли все запасы за все периоды времени, и, если они несбалансированы, сбалансируйте их так, чтобы все запасы наблюдались в одни и те же даты торговли. Это указывает на то, что некоторые наблюдения будут удалены, чтобы все акции имели наблюдения в одни и те же торговые дни.

dataset2 <- dataset %>% select(-label)
is.pbalanced(dataset2)
dataset2 <- make.pbalanced(dataset2,balance.type = "shared.times")
is.pbalanced(dataset2)

Создать предикторы

Для всех наблюдений за акциями в нашем наборе данных мы создадим инженерные характеристики: MACD, RSI, m5, m20, v1 и v5.

create_predictors <- function(df){
  df_full <- df %>% mutate(macd=MACD(Cl(df), nFast=12, nSlow=26, nSig=9, maType=SMA)[,1], 
                        m5=momentum(df$close, n=5), 
                        m20=momentum(df$close, n=20), 
                        rsi=RSI(df$close, n=14),
                        vol1=ROC(df$volume, n=1),
                        vol5=ROC(df$volume, n=5))
  return(df_full)
}

balanced_tickers <- unique(dataset2$ticker)
dataset2_full <- dataset2 %>% filter(ticker=="AAPL") %>% create_predictors() 

for(i in balanced_tickers[2:length(balanced_tickers)])
{
 dataset2_full <- rbind(dataset2_full, dataset2 %>% filter(ticker==i) %>% create_predictors())
}

dataset2_full %>% filter(date=="2014-05-21")

Наборы данных для тестирования и обучения

Создайте наборы тестовых и обучающих данных для целей прогнозирования и убедитесь, что оба набора данных сбалансированы.

stock_dates <- unique(dataset2_full$date)

test_dates <- tail(stock_dates, 250)
train_dates <- head(stock_dates, length(stock_dates)-250)

test_stocks <- dataset2_full %>% dplyr::filter(date %in% test_dates)
train_stocks <- dataset2_full %>% dplyr::filter(date %in% train_dates)
is.pbalanced(test_stocks)
is.pbalanced(train_stocks)
train_stocks <- train_stocks %>% drop_na()
panel_stocks <- pdata.frame(train_stocks, index = c("ticker", "date"))

Модель 3A: объединенная OLS

Объединенная модель для панельных данных применяет к данным метод обычных наименьших квадратов. Это самая ограничительная модель панели, так как размеры поперечного сечения игнорируются:

stocks_m3_pooled <- plm(close ~ macd + m5 + m20,  data = panel_stocks, model = "pooling")
summary(stocks_m3_pooled)
Pooled_Model <- glance(stocks_m3_pooled)

Модели с фиксированным эффектом

В моделях с фиксированными эффектами мы будем предполагать наличие ненаблюдаемой неоднородности между акциями, такой как основная компетенция каждой компании или что-то еще, что является уникальным для каждой компании и, таким образом, что-то ненаблюдаемое учитывается в цене акций каждой компании. Эта неоднородность (𝛼𝑖αi) неизвестна, но мы хотели бы исследовать ее корреляцию с созданными предикторными переменными, чтобы увидеть ее влияние на цену закрытия:

Модель 3B: Фиксированная модель — внутри оценщика

stocks_m3_within <- plm(close ~ macd + m5 + m20 + rsi + vol5,  data = panel_stocks, model = "within")
summary(stocks_m3_within)
Fixed_Model <- glance(stocks_m3_within)

Модель 3C: Фиксированная модель — Оценщик первой разницы

Оценка первой разности использует изменения периода для каждой акции, где отдельные специфические эффекты (ненаблюдаемая неоднородность) компенсируются: 𝑡− 1)yit−yi,t−1=β(xit−xi,t−1)+(eit−ei,t−1)

Глядя на результат, мы видим, что, хотя скорректированное 𝑅2R2 довольно высокое по сравнению с подобранными значениями, оно бессмысленно.

stocks_m3_fd <- plm(close ~ macd + m5 + m20 + rsi + vol1 + vol5,  data = panel_stocks, model = "fd")
summary(stocks_m3_fd)
Fixed_Model_FD <- glance(stocks_m3_fd)
fitted.values(stocks_m3_fd)[1:10]

Модель 3D: Модель со случайным эффектом

В моделях случайных воздействий предполагается отсутствие фиксированных эффектов. Индивидуальные специфические эффекты (ненаблюдаемая гетерогенность) не коррелируют с предикторными переменными и не зависят от предикторных переменных. Это привело бы к предположению, что любая остаточная вариация зависимой переменной (цена закрытия) является случайной и должна случайным образом распределяться с членом ошибки:

stocks_m3_random <- plm(close ~ macd + m5 + m20 + rsi + vol5,  data = panel_stocks, model = "random")
summary(stocks_m3_random)
Random_Model <- glance(stocks_m3_random)

Тестирование и выбор модели панели

Ниже представлен краткий обзор четырехпанельных моделей, работающих с набором данных об акциях. Выбор между объединенной моделью, моделью с фиксированным эффектом или моделью со случайным эффектом требует выполнения тестов Бреуша-Пагана-Лагранжа и теста Хаусмана. Из 4 моделей, приведенных ниже, мы отбросим модель «Первое отличие» из-за ее бессмысленных подгоночных значений.

Panel_Model_Summary <- data.frame(Pooled_Model)

Panel_Model_Summary <- rbind(Panel_Model_Summary, Fixed_Model)
Panel_Model_Summary <- rbind(Panel_Model_Summary, Fixed_Model_FD)
Panel_Model_Summary <- rbind(Panel_Model_Summary, Random_Model)


rownames(Panel_Model_Summary) <- c("Pooled Model", "Fixed Model", "First Difference Model", "Random Model")
Panel_Model_Summary

Тест множителя Бреуша-Пагана-Лагранжа (тест LM) используется для проверки гетероскедастичности в модели линейной регрессии. Нулевая гипотеза предполагает гомоскедастичность, а альтернативная гипотеза предполагает гетероскедастичность.

Во-первых, мы тестируем случайные эффекты против OLS. Из теста мы видим, что, поскольку значение p близко к 0, мы отвергаем нулевую гипотезу. Индивидуальные специфические эффекты (ненаблюдаемая гетерогенность) каждой акции значительны, и поэтому мы не должны использовать объединенную модель OLS.

plmtest(stocks_m3_pooled, effect = "individual")

Мы тестируем модель с фиксированными эффектами в сравнении с моделью OLS и снова видим, что отвергаем нулевое значение для альтернативной гипотезы, поскольку тест предполагает большую поддержку модели с фиксированными эффектами.

#LM test for fixed effects vs OLS
#significant result, more support for fixed effects model over ols
pFtest(stocks_m3_within, stocks_m3_pooled)

Из двух приведенных выше тестов мы можем отказаться от объединенной модели OLS, которая игнорирует как поперечное сечение, так и измерения временных рядов. Далее мы сравниваем модели с фиксированными эффектами и случайными эффектами. Мы делаем это с помощью теста Хаусмана, который оценивает согласованность оценок, в нашем случае оценок с фиксированным эффектом и случайных эффектов. Если нет корреляции между независимыми переменными и отдельными специфическими эффектами, то модели с фиксированным эффектом и со случайным эффектом согласуются, но модель с фиксированным эффектом неэффективна. Если есть корреляция, то модель с фиксированными эффектами непротиворечива, а модель со случайными эффектами несовместима.

Из результата мы видим, что нулевая гипотеза отвергнута. Это указывает на то, что гипотеза о том, что отдельные случайные эффекты каждой акции не коррелируют с ошибкой, не имеет поддержки. Поэтому мы выбираем альтернативную гипотезу и выбираем модель с фиксированным эффектом.

phtest(stocks_m3_random, stocks_m3_within)

Обсуждение и вывод

В этом проекте мы реализовали модели с использованием логистической регрессии, панельной регрессии и авторегрессионных моделей с использованием ARIMA.

Логистические модели, пытающиеся предсказать направление движения на следующий день, дали плохие результаты. Вряд ли какая-либо предикторная переменная была значимой, а точность классификации составляла около 52%, что вряд ли лучше, чем угадывание. Проблемы мультиколлинеарности, которые были решены, не улучшили результаты, поэтому от этой модели отказались. Некоторые улучшения возможны при использовании большего набора данных по нескольким акциям или при использовании разных целевых переменных.

Авторегрессионные модели, которые предсказывают последующие значения временного ряда акций, были более полезными. Это потребовало найти подходящую комбинацию параметров, чтобы точно соответствовать данным. Простая линейная регрессия предполагает, что можно использовать AR (1), где предиктором является предыдущее значение цены. Мы оценили коэффициенты и подобрали модель, но также отметили, что ряды не были стационарными и должны быть дифференцированы, чтобы стабилизировать среднее значение, чтобы оно соответствовало предположениям моделирования. Мы развиваем простую авторегрессионную модель AR (1), чтобы включить в структуру параметр дифференцирования, а также скользящее среднее. Подошли самые разные модели, и было обнаружено, что предпочтение отдается моделям меньшего размера. В качестве лучшей была выбрана дифференциальная модель второго порядка со структурой MA(1). Мы смогли проверить ее достоверность, разделив данные о запасах на обучающие и тестовые наборы, чтобы оценить производительность модели. Удивительно, но MA(1) стабильно фиксирует движение цены акции в пределах своих доверительных интервалов. Интервалы остаются довольно широкими, и линейный тренд не гарантирует отражения фактической цены акции в любое время, а только центрирует тренд.

Для панельной регрессии мы создали и сравнили значимость 3 моделей: объединенной МНК, модели с фиксированными эффектами и модели со случайными эффектами. В рамках фиксированной модели мы попробовали оценку первых различий, которая, хотя и объясняла наибольшую изменчивость, давала бессмысленные результаты, поэтому была отброшена. Остальные 3 модели имели аналогичное объяснение изменчивости, но, учитывая наш набор данных и его характер, должна применяться только модель с фиксированным эффектом. Тест множителя Бреуша-Пагана-Лагранжа (тест LM) и тест Хаусмана продемонстрировали поддержку этого по сравнению с моделями объединенного МНК и случайного эффекта, поскольку у каждой компании есть врожденные характеристики, влияющие на ее цену закрытия. Ограничение модели с фиксированным эффектом заключалось в том, что она не могла предсказать результаты для тестового набора данных из-за неразрешимой проблемы мультиколлинеарности с инженерным набором данных. Решение этой проблемы потребует разработки другого набора функций, и это остается для будущей работы.

Учитывая эти 3 модели, авторегрессионные модели с использованием ARIMA дали наиболее стабильные результаты. Выход каждой из трех моделей отличается, что делает сравнение каждой из них проблематичным. Логистическая модель дает бинарные результаты, панельная модель предсказывает фактические значения закрытия, а авторегрессионная модель оценивает общую динамику запасов за заданный период времени. Учитывая, что сделать достаточно точный прогноз цен акций по торговым дням — трудная задача, авторегрессионная модель ARIMA, которая дает тенденции за определенные периоды времени, является лучшим и более подходящим методом определения/оценки движения цен акций.