library(rmarkdown) library(quantmod) library(tidyverse) library(PerformanceAnalytics) library(tidyquant) library(opendatauzb) library(knitr) library(kableExtra) library(formattable) #library(RcppSimdJson)
This vignette provides an overview of a practical use of opendatauzb package's functions to work with Uzbek Stock Market Data. Unlike stock markets in developed economies, there are few resources available in Uzbekistan that are machine-friendly and able to provide Uzbek stock market prices in machine-readable formats. With this R package, we overcome these data limitations and improve productivity of equity research analysts while evaluating Uzbek stocks.
opendatauzb::RegisteredSecurities()
collects a list of securities from the Central Securities Depository database.
RegisteredSecurities()
RegisteredSecurities() %>% head(10) %>% kable()
opendatauzb::getSecurities()
provides a data frame with the list of securities from the Republican Stock Exchange "Toshkent" database
getSecurities()
getSecurities() %>% head(10) %>% kable() %>% kable_styling()
opendatauzb::ipo()
returns a data frame with public offerings in last five years.
ipo()
ipo() %>% tail(10) %>% kable() %>% kable_styling()
opendatauzb::currentBidsAsks()
returns current bid and ask prices on the Republican Stock Exchange "Toshkent" database.
currentBidsAsks()
currentBidsAsks() %>% head(10) %>% select(-5) %>% kable(results = "asis") %>% kable_styling()
opendatauzb::getMarketIndex()
downloads Uzbek stock market indices (Uzbekistan Composite Index, UCI) by sectors or all sectors. The sector name should be provided as the following (case-insensitive):
getMarketIndex(sector = "all")
getMarketIndex(sector = "all") %>% head(10) %>% kable() %>% kable_styling()
The timeframe can be specified by arguments from and to provided in "%d.%m.%Y" date format:
getMarketIndex(sector = "finance", from = "01.01.2018", to = "30.06.2020")
getMarketIndex(sector = "finance", from = "01.01.2018", to = "30.06.2020") %>% head(10) %>% kable() %>% kable_styling()
opendatauzb::getTicker()
obtains stock market prices by security code over the period given:
getTicker("UZ7011340005")
getTicker("UZ7011340005") %>% head(10) %>% select(-9, -10) %>% kable() %>% kable_styling()
getTicker("UZ7011340005", from = "01.01.2018", to = "30.06.2020")
getTicker("UZ7011340005", from = "01.01.2018", to = "30.06.2020") %>% head(10) %>% select(-9, -10) %>% kable() %>% kable_styling()
For this example, we use opendatauzb package's functions and other packages (quantmod
, PerformanceAnalytics
, tidyquant
) for financial modelling to evaluate the given set of stocks and portfolio performance. we have chosen 20 stocks, including Kvarts, Trustbank, Hamkorbank, UzSQB, ToshkentVino and others.
Using getTicker
function, we download stock prices for each of those stocks. Note: if arguments from and to are not provided, by default, both getMarketIndex()
and getTicker()
functions download stock prices from 01.01.2019 to 12.08.2020.
asset_group <- c("UZ704532K019", "UZ7045320007", "UZ7025870005", "UZ7038380000", "UZ7025770007", "UZ7015030008", "UZ7043200003", "UZ703756K015", "UZ7037560008", "UZ7016400002", "UZ7004510002", "UZ7023760000", "UZ703348K011", "UZ7033480003", "UZ7035340007", "UZ7028090007", "UZ701134K017", "UZ7011340005", "UZ701655K011", "UZ7016550004") assets <- asset_group %>% getTicker(from = "01.01.2019", to = "12.08.2020")
Having loaded stock prices, we calculate monthly returns using a tidyquant::tq_transmute()
function from tidyquant
package. Please refer to the Tidyquant vignette for information on using tidyquant
package.
As Uzbek Stock Market databases do not provide adjusted closing prices, for this example, we use closing prices. However, in real-world practice, we highly recommend calculating adjusted closing prices.
Ra <- assets %>% group_by(symbol) %>% tq_transmute(select = "Closed Price", mutate_fun = periodReturn, period = "monthly", col_rename = "Ra")
The output presents only first six rows of calculated monthly returns.
kable(head(Ra, n = 6)) %>% kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"))
After collecting data for our stocks, we download overall market index as baseline prices for our analysis.
# Baseline prices Rb <- getMarketIndex("all", from = "01.01.2019", to = "12.08.2020") %>% tq_transmute(select = price, mutate_fun = periodReturn, period = "monthly", col_rename = "Rb")
Rb %>% head(6) %>% kable() %>% kable_styling() RaRb <- left_join(Ra, Rb, by = c("Date" = "date"))
To evaluate if the stock is valued fairly considering associated risks and expected returns, we employ CAPM model. We use tidyquant::tq_performance()
function from tidyquant
package.
RaRb_capm <- RaRb %>% tq_performance(Ra = Ra, Rb = Rb, Rf = 0.15, performance_fun = table.CAPM)
RaRb_capm %>% select(1:3,5, 10, 12, 13) %>% kable() %>% kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"))
We estimate Sharpe ratio for all our stocks to see returns on investment per amount of taken risks. As a rule of thumb, the Sharpe ratio greater than 3 is classified as Excellent, an interval 2.00-2.99 is Very Good, 1.00-1.99 range is Acceptable, the ratio less than 1 is classified as Bad or Sub-optimal.
RaRb %>% tq_performance(Ra = Ra, Rb = NULL, performance_fun = SharpeRatio, Rf = 0.15) %>% formattable(list("ESSharpe(Rf=15%,p=95%)" = formatter("span", style = x ~ ifelse(x >= 3, style(color = "green", font.weight = "bold"), NA))))
Based on the ratios we calculated above, we choose two stocks for our portfolio: UZ7015030008 (MSBU) and UZ7035340007 (UZKB).
wts <- c(rep(0, 5), 0.35, #6 rep(0, 8), 0.65, #15 rep(0, 5)) portfolio_returns_monthly <- Ra %>% tq_portfolio(assets_col = symbol, returns_col = Ra, weights = wts, col_rename = "Ra") left_join(portfolio_returns_monthly, Rb, by = c("Date"="date")) %>% tq_performance(Ra = Ra, Rb = Rb, performance_fun = table.CAPM) %>% gather() %>% kable() %>% kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"))
On condition that our initial assumptions hold, let us see how 100,000 UZS investment in these stocks would grow since 1 January 2019.
portfolio_growth_monthly <- Ra %>% tq_portfolio(assets_col = symbol, returns_col = Ra, weights = wts, col_rename = "investment.growth", wealth.index = TRUE) %>% mutate(investment.growth = investment.growth * 100000)
As the graph below shows, the initial investment of 100,000 UZS in these 2 stocks in 1 January 2019 is worth around 2.2M UZS as of 30 June 2020 without inflation adjustment.
Note: These estimates are for only illustrative purposes of the practical use of opendatauzb package. The real returns on investment may rely heavily on the assumptions drawn earlier and other exogenous shocks to Uzbek Stock Market.
portfolio_growth_monthly %>% ggplot(aes(x = Date, y = investment.growth)) + geom_line(size = 2, color = palette_light()[[1]]) + labs(title = "Portfolio growth", subtitle = "35% MSBU and 65% UZKB", caption = "", x = "", y = "Portfolio Value (thousand UZS)") + geom_smooth(method = "loess") + theme_tq() + scale_color_tq() + scale_y_continuous(labels = scales::unit_format(unit = "", scale = 1e-3))
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.