Introduction to Uzbek Stock Market Data with opendatauzb package

Alisher Suyunov

2020-09-12

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.

Available securities in Uzbek Stock Market

RegisteredSecurities(): Download a full list of registered securities with ISIN and CFI codes

opendatauzb::RegisteredSecurities() collects a list of securities from the Central Securities Depository database.

RegisteredSecurities()
Issuer SecurityCode ISIN CFI last_update
" Andijon viloyati mashina-traktor parklari birlashmasi" aksiyadorlik jamiyati UZ7046520001 UZ0000000CY7 ESXXXR 11-09-2020
“1-Temir beton mahsulotlari zavodi” aksiyadorlik jamiyati UZ7042380004 UZ0000000CQ3 ESXXFR 11-09-2020
“4-sonli Montaj Boshqarmasi” aksiyadorlik jamiyati UZ705326K015 UZ0000000C74 EPXXXR 11-09-2020
“4-sonli Montaj Boshqarmasi” aksiyadorlik jamiyati UZ7053260004 UZ0000000C82 ESXXFR 11-09-2020
“Agregat zavodi” aksiyadorlik jamiyati UZ7045360003 UZ0000000FA0 ESXXFR 11-09-2020
“Agro invest sug’urta” aksiyadorlik jamiyati UZ7055650004 UZ0000000BY9 ESXXFR 11-09-2020
“Agrobank” aksiyadorlik tijorat banki UZ700156K011 UZ00000004P2 EPXXXR 11-09-2020
“Agrobank” aksiyadorlik tijorat banki UZ7001560000 UZ00000004Q0 ESXXFR 11-09-2020
“Algoritm” aksiyadorlik jamiyati UZ7043280005 UZ00000001V6 ESXXXR 11-09-2020
“Alliance-Leasing” aksiyadorlik jamiyati UZ7055590002 UZ0000000BJ0 ESXXFR 11-09-2020

getSecurities(): Download the securities listed on the Republican Stock Exchange “Toshkent”

opendatauzb::getSecurities() provides a data frame with the list of securities from the Republican Stock Exchange “Toshkent” database

getSecurities()
## 5106 securities are found. Out of which are:
## # A tibble: 4 x 2
## # Groups:   Type [4]
##   Type      n
##   <chr> <int>
## 1 BND      11
## 2 FCT     492
## 3 RPO    4425
## 4 STK     178
Type SecurityCode Ticker Issuer
STK UZ7053260004 TSMB <4-sonli Montaj Boshqarmasi> aksiyadorlik jamiyati
STK UZ705326K015 TSMB1 <4-sonli Montaj Boshqarmasi> aksiyadorlik jamiyati
STK UZ7045360003 AGZD <Agregat zavodi> aksiyadorlik jamiyati
STK UZ7001560000 AGBA <Agrobank> aksiyadorlik tijorat banki
STK UZ700156K011 AGB1 <Agrobank> aksiyadorlik tijorat banki
STK UZ7055590002 ALLS <Alliance-Leasing> aksiyadorlik jamiyati
STK UZ7045320007 ALSM <Alskom> sug’urta kompaniyasi aksiyadorlik jamiyati
STK UZ704532K019 ALS1 <Alskom> sug’urta kompaniyasi aksiyadorlik jamiyati
STK UZ7047650005 ABKZ <Andijon biokimyo zavodi> aksiyadorlik jamiyati
STK UZ7018010007 ANDD <Andijon dori-darmon> aksiyadorlik jamiyati

ipo(): Obtain schedule of public offerings (IPO/SPO/PO (the government shares))

opendatauzb::ipo() returns a data frame with public offerings in last five years.

ipo()
Code Title Отмена подписки Дата начала подписки Дата окончания подписки Этап подписки Валюта Цена предложения Депонирование (%) Объем выставленных на подписку (ед.) Объем выкупленных по подписке(ед.) Дата включения в биржевой котировальный лист
55 UZ7038450001 UZPARTA’MINOT AJ N 28.08.2020 11.09.2020 1 UZS 31640,81 100 (%) 403 200 0 16.09.2020
56 UZ7030550006 Asaka yog’ AJ N 02.09.2020 16.09.2020 1 UZS 9001,87 100 (%) 2 206 170 0 21.09.2020
57 UZ7026620003 Farg’ona yog’-moy AJ N 07.09.2020 21.09.2020 1 UZS 28117,18 100 (%) 3 095 500 0 24.09.2020
58 UZ702662K016 Farg’ona yog’-moy AJ N 07.09.2020 21.09.2020 1 UZS 28117,18 100 (%) 1 504 0 24.09.2020
59 UZ7005950009 JSC Uzpartamponaj N 07.09.2020 21.09.2020 1 UZS 5387,88 100 (%) 3 041 090 0 24.09.2020
60 UZ7032740001 Buxoro ta’mirlash mexanika zavodi AJ N 07.09.2020 21.09.2020 1 UZS 12859,20 100 (%) 1 891 785 0 24.09.2020
61 UZ7032730002 O’ZPARAVTOTRANS AJ N 07.09.2020 07.10.2020 1 UZS 283507,50 100 (%) 152 166 0 12.10.2020
62 UZ7017850007 URGANCH YOG’-MOY AJ N 09.09.2020 23.09.2020 1 UZS 8279,20 100 (%) 18 645 786 0 28.09.2020
63 UZ7018260008 Buxoroparranda AJ N 10.09.2020 29.09.2020 1 UZS 13136,92 100 (%) 459 630 0 05.10.2020
64 UZ7036030003 ANDIJONYOG’MOY AJ N 11.09.2020 25.09.2020 1 UZS 137054,18 100 (%) 243 163 0 30.09.2020

currentBidsAsks(): Watch current Bids and Asks for stocks

opendatauzb::currentBidsAsks() returns current bid and ask prices on the Republican Stock Exchange “Toshkent” database.

currentBidsAsks()
Рынок Площадка Код ЦБ Эмитент Лучшая цена продажи Общее кол-во ЦБ на продажу Лучшая цена покупки Общее кол-во ЦБ на покупку

Market Benchmark

getMarketIndex(): Download stock market indices over the period given across sectors

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):

  • all
  • finance
  • industry
  • agriculture
  • construction
  • social
  • transport
  • trade
  • other
getMarketIndex(sector = "all")
## Uzbekistan Composite Index (Sector: All) will be downloaded for 01.01.2020-12.09.2020
date open_price high_price low_price price previous_day_price marketcap trading_volume trading_value
2020-01-03 0 0 0 643.15 641.97 52048360492952.33 121303 65763290.37
2020-01-04 0 0 0 639.75 643.15 51714672407463.76 1355928 106731028.16
2020-01-06 0 0 0 639.45 639.75 51690319615649.21 64672 201229179.81
2020-01-07 0 0 0 631.02 639.45 51003443579354.92 1210672 204705056.56
2020-01-08 0 0 0 626.86 631.02 50664174864300.91 597241 743946494.86
2020-01-09 0 0 0 625.94 626.86 50593775911126.8 311042 97060299.18000001
2020-01-10 0 0 0 627.87 625.94 50751392079610.95 3859464 261145216.77
2020-01-13 0 0 0 632.62 627.87 51138187340933.22 171658 116101857.37
2020-01-14 0 0 0 625.69 632.62 50709330434036.91 154980 91653997.59999999
2020-01-15 0 0 0 631.40 625.69 51174011596455.78 338382 490836761.29

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")
## Uzbekistan Composite Index (Sector: Finance) will be downloaded for 01.01.2018-30.06.2020
date open_price high_price low_price price previous_day_price marketcap trading_volume trading_value
2018-01-04 0 0 0 988.93 988.93 9527326459319.529 20 34000.0
2018-01-05 0 0 0 988.93 988.93 9527326459319.529 19537350 5079711000.0
2018-01-06 0 0 0 988.93 988.93 9527326459319.529 0 0.0
2018-01-08 0 0 0 988.93 988.93 9527326459319.529 0 0.0
2018-01-09 0 0 0 988.93 988.93 9527326459319.529 0 0.0
2018-01-10 0 0 0 988.93 988.93 9527326459319.529 0 0.0
2018-01-11 0 0 0 988.93 988.93 9527326459319.529 0 0.0
2018-01-12 0 0 0 988.93 988.93 9527326459319.529 8800000 88000000.0
2018-01-15 0 0 0 988.93 988.93 9527326459319.529 77708 12044740.0
2018-01-16 0 0 0 988.93 988.93 9525326119319.529 995 118405.0

getTicker(): Load stock market prices for certain timeframe

opendatauzb::getTicker() obtains stock market prices by security code over the period given:

getTicker("UZ7011340005")
## New names:
## * `` -> ...9
## * `` -> ...10
## UZ7011340005 has been downloaded for 01.01.2020-12.09.2020
Date Closed Price Change Trading Volume (shr) Trading Value (KHR) Opened High Low symbol
2020-01-03 36.00 0.00 84 3106.17 36.99 36.99 36.0 UZ7011340005
2020-01-04 37.00 1.00 8345 309180.00 32.00 38.00 32.0 UZ7011340005
2020-01-06 36.70 -0.30 122 4453.60 36.50 36.90 36.5 UZ7011340005
2020-01-07 33.00 -3.70 712312 23566961.00 37.00 37.00 33.0 UZ7011340005
2020-01-08 36.50 3.50 472 17040.92 36.78 36.78 30.0 UZ7011340005
2020-01-09 36.50 0.00 18146 662725.00 37.00 37.00 35.0 UZ7011340005
2020-01-10 34.99 -1.51 3737160 119633828.98 33.00 34.99 32.0 UZ7011340005
2020-01-13 35.00 0.01 36026 1265501.90 36.00 36.30 35.0 UZ7011340005
2020-01-14 35.99 0.99 201 7191.20 33.00 35.99 33.0 UZ7011340005
2020-01-15 35.90 -0.09 3443 123610.20 36.00 36.00 35.9 UZ7011340005
getTicker("UZ7011340005", 
          from = "01.01.2018", 
          to = "30.06.2020")
Date Closed Price Change Trading Volume (shr) Trading Value (KHR) Opened High Low symbol
2018-01-04 155 0 0 0 155 155 155 UZ7011340005
2018-01-05 155 0 0 0 155 155 155 UZ7011340005
2018-01-06 155 0 0 0 155 155 155 UZ7011340005
2018-01-08 155 0 0 0 155 155 155 UZ7011340005
2018-01-09 155 0 0 0 155 155 155 UZ7011340005
2018-01-10 155 0 0 0 155 155 155 UZ7011340005
2018-01-11 155 0 0 0 155 155 155 UZ7011340005
2018-01-12 155 0 0 0 155 155 155 UZ7011340005
2018-01-15 155 0 57533 8917615 155 155 155 UZ7011340005
2018-01-16 155 0 0 0 155 155 155 UZ7011340005

Constructing a portfolio with Uzbek Stocks

Creating a data frame with stock prices

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 starting from 01.01.2019.

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 %>%
  lapply(getTicker, from = "01.01.2019", to = "12.08.2020") %>%
  bind_rows()

Having loaded stock prices, we calculate monthly returns using a tidyquant::tq_transmute() function from tidyquant package. Please refer to the link for more 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.

symbol Date Ra
UZ704532K019 2019-01-31 -0.0029851
UZ704532K019 2019-02-28 0.0059880
UZ704532K019 2019-03-29 0.0000000
UZ704532K019 2019-04-30 -0.0059524
UZ704532K019 2019-05-31 -0.0131737
UZ704532K019 2019-06-28 -0.0048544

Market Index (Uzbekistan Composite Index, UCI)

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")
## Uzbekistan Composite Index (Sector: All) will be downloaded for 01.01.2019-12.08.2020
date Rb
2019-01-31 -0.6157297
2019-02-28 0.0345058
2019-03-29 0.7903746
2019-04-30 0.0249493
2019-05-31 -0.0012299
2019-06-28 -0.0055492

Building the Capital Asset Pricing Model (CAPM)

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)
symbol ActivePremium Alpha Beta InformationRatio TrackingError TreynorRatio
UZ704532K019 0.0609 -0.1578 0.0016 0.0753 0.8091 -535.6676
UZ7045320007 0.0609 -0.1578 0.0016 0.0753 0.8091 -535.6676
UZ7025870005 1.2321 -0.1104 -0.4291 0.8328 1.4796 1.6130
UZ7038380000 -0.8227 -0.1539 0.5325 -0.8446 0.9741 NaN
UZ7025770007 -0.1484 -0.1854 -0.0782 -0.1585 0.9363 11.6321
UZ7015030008 0.1465 -0.0318 0.0532 0.0833 1.7587 -17.9109
UZ7043200003 1.0961 -0.0922 -0.0542 1.1193 0.9793 12.8673
UZ703756K015 0.1594 -0.1416 0.0582 0.2094 0.7614 -14.7441
UZ7037560008 0.1594 -0.1416 0.0582 0.2094 0.7614 -14.7441
UZ7016400002 1.9330 0.0536 0.5146 1.3571 1.4244 -1.0845
UZ7004510002 -0.0699 -0.1832 -0.1227 -0.0724 0.9663 7.3111
UZ7023760000 9.2425 0.3422 -0.2486 2.0382 4.5347 1.8504
UZ703348K011 0.6971 -0.0746 -0.0318 0.5024 1.3877 24.7448
UZ7033480003 0.6971 -0.0746 -0.0318 0.5024 1.3877 24.7448
UZ7035340007 25964.5829 4.5432 -0.4637 913.9865 28.4081 -1991.5937
UZ7028090007 0.8958 -0.1484 -0.4853 0.6497 1.3787 1.5272
UZ701134K017 0.1397 -0.1368 -0.0284 0.1270 1.0997 30.5495
UZ7011340005 0.1397 -0.1368 -0.0284 0.1270 1.0997 30.5495
UZ701655K011 0.1629 -0.1477 -0.0736 0.1591 1.0241 11.7079
UZ7016550004 0.1629 -0.1477 -0.0736 0.1591 1.0241 11.7079

Calculating Sharpe ratio for individual stocks

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))))
symbol ESSharpe(Rf=15%,p=95%) StdDevSharpe(Rf=15%,p=95%) VaRSharpe(Rf=15%,p=95%)
UZ704532K019 -1.12789189 -3.75232219 -1.78127794
UZ7045320007 -1.12789189 -3.75232219 -1.78127794
UZ7025870005 -0.12947160 -0.17778980 -0.14778762
UZ7038380000 -0.23712348 -0.79025799 -0.36825494
UZ7025770007 -0.69265057 -1.60678872 -0.84967804
UZ7015030008 -0.05814506 -0.08512571 -0.07265861
UZ7043200003 -0.45977881 -0.58180582 -0.69660766
UZ703756K015 -2.07009673 -3.84148495 -2.48432885
UZ7037560008 -2.07009673 -3.84148495 -2.48432885
UZ7016400002 -0.01706879 -0.04132266 -0.68890280
UZ7004510002 -0.84021409 -1.52712615 -0.96107323
UZ7023760000 0.26727994 0.24109435 0.34372057
UZ703348K011 -0.15468606 -0.21757520 -0.19196976
UZ7033480003 -0.15468606 -0.21757520 -0.19196976
UZ7035340007 3.64833121 0.44626039 3.64833121
UZ7028090007 -0.21286472 -0.35202905 -0.45154997
UZ701134K017 -0.39318161 -0.62773007 -0.54169233
UZ7011340005 -0.39318161 -0.62773007 -0.54169233
UZ701655K011 -0.48700581 -0.84285552 -0.59469028
UZ7016550004 -0.48700581 -0.84285552 -0.59469028

(Single) Portfolio performance

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"))
key value
ActivePremium 5.1232
Alpha 0.6238
AnnualizedAlpha 334.9753
Beta 0.2671
Beta- 0.0067
Beta+ -0.8533
Correlation 0.0229
Correlationp-value 0.9237
InformationRatio 0.5737
R-squared 0.0005
TrackingError 8.9296
TreynorRatio 15.7192

Portfolio growth

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.