Про ушедший 2023 🎄
2023 год завершился весьма успешно для российского инвестора: индекс ММВБ прибавил 45% частично скомпенсировав падение 2022 года. Таким образом, за последние 8 лет (с 2016 года) индекс показал доходность ~6.9%. Мои личные счета также зафиксировали рост в этом году, а за прошедшие 8 лет уже набежало 14-15% среднегодовых. Естественно, свою доходность я рассчитываю с учетом дивидендов и купонных выплат тогда как индекс ММВБ учитывает такие денежные потоки опосредованно. В любом случае, позитив на рынке и у меня лично присутствует, а это придает мотивации делиться своими соображениями о закономерностях, происходящих на финансовых рынках, подкрепленных каркасом из объективных данных.
Наверное многие слышали, что рынок бывает бычьим и еще медвежьим то есть существуют чуть ли не две мистические силы, которые толкают рынок вниз или вверх. Признаюсь, с эзотерическими практиками мои взаимоотношения не очень складываются. Мне нравится думать, что всему можно найти некое логическое объяснение. В моей картине мира носителями настроений являются люди, часть которых настроены всегда позитивно, часть всегда негативно к экономике РФ или даже к мировой экономике. Одни рисуют радужное будущее с розовыми пони, катающихся на радуге, другие – наоборот рисуют мрачный ужас пришествия четырех всадников апокалипсиса. Между этими двумя крайностями находится менее фанатичный слой людей, которых в зависимости от момента увлекают то медвежьи, то бычьи настроения. Где-то в стороне от этого всего тусуются профессиональные инвесторы, которые цинично рубят бабло, пока рынок бросает из жара в холод и обратно.
Ранее я уже упоминал, что медведям живется несколько сложнее, чем быкам в силу органичного роста рынка за счет инфляции и неустанного роста ВВП. Это конечно не значит, что механизм роста ВВП не может сломаться. В конечном итоге, все рано или поздно ломается, но хочется верить, что человечество найдет выход из любого тупика и рынки будут чаще расти чем падать. В такой картине финансового мира возникает вопрос: когда собственно входить и выходить в рынок? Для простоты я буду говорить о входе в рынок акций в противовес активам фиксированной доходности (облигации, вклады и тому подобное). Естественно, никто не отменяет личные нормативы ликвидности, которые позволят в любой рыночной ситуации вытащить деньги с рынка без ощутимых потерь и множество других вопросов типа налогообложения, крупных покупок типа квартиры, игры с плечом и прочее бу бу бу …
Валовый внутренний продукт 🛍️
Итак, для того чтобы понять когда оптимально входить в рынок акций или выходить нужен какой-то интегральный показатель, способный дать оценку всей экономики в совокупности, например ВВП. Насколько такой показатель будет уместен для бенчмарка с индексом ММВБ? Как известно, ВВП включает в себя итоги деятельности всех организаций и компаний, в то же время, далеко не все организации – являются публичными и осуществляют эмиссию акций на ММВБ. Более того, не все компании котирующиеся на бирже ММВБ попадают в листинг индекса ММВБ. С другой стороны, экономика – это нечто, напоминающее огромную сеть экономических агентов и эластичных взаимосвязей. Проблемы в одном секторе в некоторой степени перекидываются в другой сектор и наоборот. Действительно, если какой-то условный ларек “ИП Хомяков” закроется, то это сократит потребление услуг банков и продуктов нефтяных компаний, которые были поставщиками услуг/товаров для этого ларька. Конечно, эффект будет не существенный, если речь про один единственный ларек, но если их десятки тысяч … Естественно, если на место “ИП Хомяков” придет “ИП Бурундуков” или сетевой магазин “Десяточка”, то принципиально картина не изменится. Таким образом, в качестве условного ориентира, думаю, можно использовать ВВП.
Конечно, не достаточно просто выбрать ВВП в качестве равновесного ориентира, нужно также немного поколдовать с данными. Самые подробные подробности можно будет найти в кладовой кода R в самом низу ⬇️ заметки. Основные идеи крупными мазкам:
- Аннотация к данным по ВВП гласит: Валовой внутренний продукт (в ценах 2021 г. с исключением сезонного фактора, млрд.руб.) 2011-2023гг.. Это означает, что не нужно возиться с сезонностью: за меня это уже сделал Росстат и также не нужно дисконтировать рост ВВП на инфляцию потому как Росстат привел показатель к ценам 2021 года. Ну и замечательно.
- В распоряжении имеются сведения о ВВП с дискретностью по кварталам, в то время как индекс ММВБ за приличный период можно найти с дискретностью по месяцам. Поэтому график индекса ММВБ представлен как ступенчатая кривая со значениями на конец последнего дня месяца, а показатель ВВП будет представлен как ступенчатая кривая со значениями на конец последнего дня квартала.
- Индекс ММВБ следует очистить от инфляции для чего будет использован соответствующий индекс потребительских цен. Может возникнуть вопрос: почему не использовался дефлятор ВВП или индекс промышленных цен? Дело в том, что индекс ММВБ интересует меня как розничного инвестора и мне интересно следить за ростом собственного капитала, дисконтированного на размер моей т.е. потребительской инфляции.
- Сведения о ВВП публикуются с некоторым запозданием, например, на момент написания этой заметки (январь 2024) опубликованы данные только за 3-ий квартал 2023, что несколько удручает так как хочется знать насколько рынок относительно ВВП перекуплен или перепродан именно сейчас и на некоторый ощутимый горизонт будущего. Для того чтобы нивелировать этот момент можно использовать прогноз роста ВВП. Я решил взять прогноз ВВП от ЦБ РФ, который обычно является весьма консервативным.
- Наконец, для того чтобы индекс ММВБ наложить на показатель ВВП в едином масштабе необходимо найти некоторое равновесие, которое проще всего получить через простую линейную регрессию.
Выводы 🍪
В итоге получился симпатичный индекс ЭЙФОРИИ/ОТЧАЯНИЯ и вот, что можно с помощью этого индекса подметить:
- Рынок почти всегда предвкушает рост или падение ВВП, что не удивительно т.к. экономика – это весьма инерционный механизм. В то же время рынок почти всегда из стадии ЭЙФОРИИ сваливается в фазу ОТЧАЯНИЯ и наоборот. Этому есть вполне логичное объяснение: при наступления кризисных признаков компании прежде всего снижают дивидендные выплаты, что существенно бьет по настроениям инвесторов. Наоборот, при перспективах выхода из кризиса компании начинают резко увеличивать дивидендные выплаты.
- Очевидно, что лучше всего покупать акции на пике ОТЧАЯНИЯ и продавать на пике ЭЙФОРИИ, но точно такой момент определить достаточно сложно. Кроме того, нет никаких гарантий, что один цикл сменит другой. Например, период с 2013 года по 2019 год ознаменовался затяжной депрессией, хотя в экономике дела шли не так уж и плохо.
- В 2024 рынок может вырасти еще на 15%+ с текущих ~3100 пунктов к равновесному уровню ~3500-3600 и это будет неплохой точкой для фиксации прибыли и частичного выхода из рынка акций.
Исходный код заметки
# Необходимые библиотеки
library(rusquant)
library(tidyverse)
library(patchwork)
# Индекс потребительский цен (наиболее свежие только в виде Excel файла)
# https://rosstat.gov.ru/storage/mediabank/ipc_kv3_2005-2023.xlsx
PI <- c("109,50", "109,54", "108,11", "106,68", NA, "103,86", "103,82", "106,03", "106,53", NA, "107,12", "107,16", "106,35", "106,39", NA, "106,40", "107,58", "107,68", "109,58", NA, "116,20", "115,82", "115,69", "114,48", NA, "108,35", "107,35", "106,83", "105,75", NA, "104,63", "104,19", "103,37", "102,57", NA, "102,24", "102,37", "102,98", "103,87", NA, "105,16", "104,99", "104,29", "103,44", NA, "102,42", "103,11", "103,54", "104,44", NA, "105,55", "106,02", "106,85", "108,31", NA, "111,54", "116,94", "114,36", "112,18", NA, "108,62", "102,69", "105,15")
# Данные по ВВП (наиболее свежие только в виде Excel файла)
# https://rosstat.gov.ru/storage/mediabank/VVP_kvartal_s_1995.xlsx
GDP <- c("29 045,8", "29 287,4", "29 600,4", "29 865,0", "30 327,8", "30 394,4", "30 675,9", "30 671,9", "30 890,6", "30 997,8", "31 002,1", "31 227,4", "31 126,8", "31 339,6", "31 137,8", "31 152,0", "30 874,9", "30 738,0", "30 734,9", "30 655,0", "30 706,8", "30 744,7", "30 779,0", "30 992,6", "31 081,3", "31 245,7", "31 506,7", "31 511,1", "31 920,1", "32 011,5", "32 221,5", "32 360,5", "32 580,1", "32 678,4", "33 005,2", "32 909,8", "32 836,5", "30 377,5", "32 574,8", "32 841,0", "33 079,4", "33 604,7", "33 777,4", "34 116,4", "34 161,5", "32 594,2", "32 827,0", "33 210,2", "33 582,0", "33 895,1", "34 197,2")
# Пакет rusquant позволяет удобно забрать индекс ММВБ с сайта Finam с месячной дискретностью
IMOEX <- getSymbols("IMOEX", from="2011-01-01", src = "Finam", period = "month", auto.assign = F)
# Подготовка индекса потребительской инфляции
PI1 <- na.omit(PI) |>
str_replace(",", ".") |>
as.numeric() |>
tibble(PI=_) |>
mutate(yearqtr = as.yearqtr(2011.25 + seq(0, 50)/4), qtr = quarter(yearqtr)) |> # создания индекса для дат
group_by(qtr) |> # Индекс дан год к году -> нужно перевести в индекс, накопленным итогом
mutate(PI_cs = cumprod(PI/1e2)) # 1. получение накопленного итога 2. перевод из процентов в десятичный вид
# Подготовка индекса ММВБ инфляции
IMOEX1 <- na.locf(IMOEX) |>
period.apply(INDEX = endpoints(IMOEX, "months"), last) |> # в каждом месяце остается последнее наблюдение
as_tibble(rownames = "IMOEX") |>
select(date = IMOEX, IMOEX = IMOEX.Close) |>
mutate(date = as.Date(date))
# Подготовка данных ВВП
GDP1 <- str_replace(GDP, ",", ".") |> str_remove(" ") |>
as.numeric() |>
tibble(GDP=_) |>
mutate(yearqtr = as.yearqtr(2011 + seq(0, 50)/4)) # создания индекса для дат
# Прогноз ВВП ЦБ
# 2023 - 3.1%, 2024 - 1.3%
# https://cbr.ru/statistics/ddkp/mo_br/
pred <- tibble(date = as.yearqtr(2023.75 + seq(0, 5)/4)|> as.Date() - 1,
GDP_pred = slice_tail(GDP1, n=1)[["GDP"]]*c(1, 1.00775, 1.00775+0.00325*1:4))
# Объединение данных
all <- left_join(GDP1, PI1, by = "yearqtr") |> # данные ВВП стыкуются с инфляцией по ключам год-квартал
mutate(date = as.Date(yearqtr + .25) - 1) |> # квартальные даты - последний день квартала
full_join(IMOEX1, by = "date") |> # объединение по датам (все в кучу, но так и задумано)
arrange(desc(date)) |>
mutate(across(c(GDP, IMOEX, PI_cs), ~accumulate(., \(out, input)if(is.na(input))out else input)), # заполнение пропусков
IMOEX = IMOEX/PI_cs) # дисконтирование индекса ММВБ на инфляцию
# Модель линейной регрессии
fit <- lm(IMOEX ~ GDP, all)
# summary(fit) # коэффициент детерминации не велик, но значимость модели подтверждается
# plot(fit) # модель не идеальна: наблюдается гетероскедастичность
mdl <- coef(fit)
# График динамики показателей ВВП и индекса ММВБ
p1 <- mutate(all, GDP_mdl = GDP*mdl[2]+mdl[1],
signal = GDP_mdl - IMOEX) |>
ggplot(aes(x = date)) +
geom_step(aes(y = GDP_mdl, col = "ВВП"), direction = "vh") +
geom_step(aes(y = IMOEX, col="ММВБ")) +
geom_step(data = pred, aes(y = GDP_pred*mdl[2]+mdl[1], col="Прогноз ВВП"), linewidth = .3) +
geom_point(data = pred, aes(y= GDP_pred*mdl[2]+mdl[1]), col=my_pal[6], size = .5) +
scale_y_continuous(sec.axis = sec_axis(name = "ВВП, трлн. ₽", ~(.-mdl[1])/mdl[2]/1e3)) +
scale_x_date(date_breaks = "1 year", date_labels = "%Y") +
scale_color_manual(values = c("ВВП"=my_pal[2], "ММВБ"=my_pal[1], "Прогноз ВВП" = my_pal[6])) +
labs(fill ="", col="", y = "Индекс ММВБ", x = "", caption = "Индекс ММВБ дисконтирован на инфляцию") +
theme(legend.position = "top")
# График индекса эйфории и отчаяния
p2 <- mutate(all, GDP_mdl = GDP*mdl[2]+mdl[1],
signal = GDP_mdl - IMOEX) |>
ggplot(aes(x = date)) +
geom_col(aes(y = signal, col = if_else(signal < 0, "ЭЙФОРИЯ", "ОТЧАЯНИЕ"),
fill = if_else(signal < 0, "ЭЙФОРИЯ", "ОТЧАЯНИЕ"))) +
annotate(x = as.Date("2020-01-01"), y = 200, geom = "text", label = "ЭЙФОРИЯ", col = my_pal[3], hjust=0) +
annotate(x = as.Date("2022-03-01"), y = -200, geom = "text", label = "ОТЧАЯНИЕ", col = my_pal[5], hjust=0) +
scale_color_manual(values = c("ЭЙФОРИЯ"=my_pal[3], "ОТЧАЯНИЕ"=my_pal[5])) +
scale_x_date(date_breaks = "1 year", date_labels = "%Y", limits = c(as.Date("2011-01-01"), as.Date("2025-01-01"))) +
scale_fill_manual(values = c("ЭЙФОРИЯ"=my_pal[3], "ОТЧАЯНИЕ"=my_pal[5])) +
labs(fill ="", col="", y = "Индекс ЭЙФОРИИ", x = "") +
theme(legend.position = "top")
# Потребительская инфляция
p3 <- ggplot(all, aes(date, PI_cs)) +
geom_step(col = my_pal[1]) +
scale_y_continuous(limits=c(1, 2.5), labels = scales::label_percent()) +
scale_x_date(date_breaks = "1 year", date_labels = "%Y", limits = c(as.Date("2011-01-01"), as.Date("2025-01-01"))) +
labs(y = "Индекс цен", x = "Квартал")
# Итоговый график - все вместе
p1/p2/p3 + plot_layout(heights = c(4,1,1))
Простой способ узнать о новых публикациях – подписаться на Telegram-канал: