1. Dữ liệu tài chính

Dữ liệu tài chính (Financial Data) bao gồm dữ liệu giá và tất cả các thông tin liên quan khác đến các tài sản tài chính được báo cáo bởi các tổ chức như sàn giao dịch chứng khoán. Dữ liệu này cho phép nhà đầu tư và nhà giao dịch cập nhật giá cả mới nhất và xem xu hướng lịch sử của các công cụ như cổ phiếu, trái phiếu, chứng khoán phái sinh và tiền tệ. Dữ liệu tài chính không chỉ được sử dụng trong giao dịch thời gian thực để đưa ra quyết định mua hoặc bán tức thời mà còn được dùng để dự báo xu hướng giá và tính toán rủi ro thị trường đối với danh mục đầu tư. Một trong những loại dữ liệu tài chính được quan tâm nhiều nhất chính là giá cổ phiếu (Equity Price). Dưới đây là một ví dụ về loại dữ liệu này cho mã chứng khoán của SSI Securities Corporation có mã là SSI trên https://finance.vietstock.vn:

Các dữ liệu tài chính là dữ liệu thô cho ít nhất ba mảng công việc quan trọng thường được thực hiện bởi các quỹ đầu tư, nhà đầu tư cá nhân cũng như các nhà đầu tư có tổ chức:

Phân tích Cơ bản. Dữ liệu tài chính là không thể thiếu để thực hiện phân tích cơ bản (Fundamental Analysis). Hình thức phân tích này bao gồm việc đào sâu vào các báo cáo tài chính để đánh giá sức khỏe tài chính của một công ty. Các chỉ số cơ bản như lợi nhuận, tăng trưởng doanh thu, dòng tiền và tỷ suất sinh lời trên vốn chủ sở hữu được xem xét để đánh giá hiệu suất và ổn định tài chính của công ty (Ross et al., 2019). Quá trình này giúp các nhà đầu tư đưa ra quyết định về việc mua hoặc bán cổ phiếu dựa trên đánh giá giá trị nội tại của các tài sản tài chính.

Phân tích thị trường. Dữ liệu tài chính cũng rất quan trọng trong việc phân tích xu hướng của thị trường (Market Analysis). Ví dụ, dữ liệu thị trường tổng hợp, như vốn hóa thị trường và các chuyển động chỉ số, cung cấp cái nhìn sâu sắc về tình hình thị trường tổng thể và tâm lý nhà đầu tư (Fama & French, 2015). Dữ liệu này hỗ trợ trong việc hiểu các chu kỳ thị trường và dự đoán các xu hướng thị trường.

Quản trị rủi ro. Dữ liệu tài chính đóng vai trò quan trọng trong quản trị rủi ro (Risk Management). Các công ty và tổ chức tài chính dựa vào dữ liệu lịch sử và thời gian thực để đánh giá và giảm thiểu rủi ro liên quan đến danh mục tài chính của họ (Damodaran, 2016). Bằng cách phân tích dữ liệu từ các sự kiện trước đây, các nhà phân tích tài chính có thể dự báo các rủi ro tiềm ẩn, do đó cho phép thực hiện các biện pháp phòng ngừa.

2. Simple và Log Return

Trong đầu tư tài chính, quản trị danh mục đầu tư cũng như quản trị rủi ro thì việc đo lường lợi nhuận của một tài sản tài chính hoặc của một danh mục đầu tư là quan trọng. Hai phương pháp phổ biến để tính toán lợi nhuận là simple return (lợi nhuận đơn giản) và log return (lợi nhuận logarit). Mỗi phương pháp có cách tính toán và ứng dụng riêng đại diện cho những góc nhìn khác nhau về hiệu suất đầu tư.

Simple Return là cách tính lợi nhuận cơ bản và trực quan nhất. Được tính bằng cách lấy giá trị cuối kỳ trừ đi giá trị đầu kỳ, sau đó chia cho giá trị đầu kỳ. Công thức đơn giản của simple return là:

\[{Simple Return} = \frac{P_t - P_{t-1}}{P_{t-1}}\]

trong đó \(P_t\) là giá trị tài sản tại thời điểm t và \(P_{t-1}\) là giá trị tài sản tại thời điểm ngay trước đó. Simple return giúp nhà đầu tư dễ dàng hiểu và so sánh hiệu suất của các khoản đầu tư khác nhau trong ngắn hạn (Bodie, Kane & Marcus, 2014).

Log Return, hay lợi nhuận logarit, lại sử dụng logarit tự nhiên để tính toán lợi nhuận, với công thức:

\[{Log Return} = \ln\left(\frac{P_t}{P_{t-1}}\right)\]

Log return có ưu điểm là phản ánh rõ hơn sự biến động của giá trị tài sản theo thời gian dài. Nó có tính chất cộng dồn, nghĩa là tổng các log return trong một khoảng thời gian sẽ bằng log return của toàn bộ khoảng thời gian đó. Điều này đặc biệt hữu ích khi phân tích chuỗi thời gian và mô hình hóa tài chính, bởi log return giúp xử lý dữ liệu biến động một cách mượt mà hơn và phù hợp cho các phân tích thống kê (Hull, 2015). Trong thực tế, lựa chọn giữa simple return và log return phụ thuộc vào mục tiêu phân tích của nhà đầu tư. Simple return đơn giản và dễ hiểu, thích hợp cho các phân tích ngắn hạn. Trong khi đó, log return cung cấp một góc nhìn chính xác hơn về sự biến động và hiệu suất của tài sản trong dài hạn.

Dưới đây là một ví dụ về tính toán hai loại return này từ bộ dữ liệu thực được được cung cấp bởi https://bvsc.com.vn (có thể download bộ dữ liệu này tại đây bằng cách sử dụng R:

# Làm sạch môi trường R: 

rm(list = ls())

# Chỉ ra đường dẫn đến dữ liệu (Download tại https://www.mediafire.com/file/os9d5hfxty04vxg/HOSE.csv/file): 

dataPath <- "E:/QPM_chap1/HOSE.csv" 

# Load một số R packages: 

library(readr) # Package chứa các hàm load dữ liệu ở định dạng csv. 
library(lubridate) # Package xử lí dữ liệu date-time. 
library(dplyr) # Package xử lí và biến đối dữ liệu. 
library(ggplot2) # Package cho data visualization. 
library(kableExtra) # Package cho trình bày các table. 

# Đọc dữ liệu: 

priceData <- read_csv(dataPath)

# Một số quan sát: 

priceData %>% 
  head() %>% 
  kbl(caption = "Table 1: Mẫu dữ liệu lịch sử cho các cổ phiếu") %>%
  kable_classic(full_width = FALSE, html_font = "Cambria")
Table 1: Mẫu dữ liệu lịch sử cho các cổ phiếu
TICKER DATE OPEN HIGH LOW CLOSE VOLUME
AAA 3/1/2018 33.0 33.15 32.50 32.95 144331
AAA 8/1/2018 32.6 33.60 32.25 33.55 220489
AAA 9/1/2018 33.6 34.00 33.55 33.95 164117
AAA 10/1/2018 34.0 34.15 33.50 34.00 118541
AAA 5/2/2018 28.7 29.00 26.85 26.85 90020
AAA 6/2/2018 25.0 26.40 25.00 25.00 151986

Bộ dữ liệu này cột DATE đang ở dạng character/text. Chúng ta cần convert bộ dữ liệu này về bản chất date-time bằng cách tạo ra cột dateYMD và lấy ra dữ liệu chỉ cho mã cổ phiếu AAA như sau:

# Tạo cột biến mới dateYMD: 

priceData %>% mutate(dateYMD = dmy(DATE)) -> priceData

# Lấy ra dữ liệu tài chính cho AAA: 

priceData %>% filter(TICKER == "AAA") -> priceAAA

# Một số quan sát: 

priceAAA %>% 
  head() %>% 
  kbl(caption = "Table 2: Mẫu dữ liệu lịch sử cho mã AAA") %>%
  kable_classic(full_width = FALSE, html_font = "Cambria")
Table 2: Mẫu dữ liệu lịch sử cho mã AAA
TICKER DATE OPEN HIGH LOW CLOSE VOLUME dateYMD
AAA 3/1/2018 33.0 33.15 32.50 32.95 144331 2018-01-03
AAA 8/1/2018 32.6 33.60 32.25 33.55 220489 2018-01-08
AAA 9/1/2018 33.6 34.00 33.55 33.95 164117 2018-01-09
AAA 10/1/2018 34.0 34.15 33.50 34.00 118541 2018-01-10
AAA 5/2/2018 28.7 29.00 26.85 26.85 90020 2018-02-05
AAA 6/2/2018 25.0 26.40 25.00 25.00 151986 2018-02-06

Chúng ta có thể xem xu hướng giá (đóng cửa) của mã AAA bằng line plot sau:

priceAAA %>% 
  ggplot(aes(x = dateYMD, y = CLOSE)) + 
  geom_line() + 
  labs(title = "Figure 1: Biến động giá của mã AAA", 
       subtitle = "Đơn vị tính: Ngàn VND", 
       caption = "Source: https://bvsc.com.vn")

Tính tính toán Simple Return và Log Return chúng ta có thể chọn giá đóng cửa làm base line. Sử dụng hàm dplyr::lead() để tìm giá của ngày liền kề trước đó rồi tính toán các return này:

# Tính Simple và Log Return cho mã cổ phiếu AAA: 
priceAAA %>% 
  mutate(lagPrice = lag(CLOSE, n = 1)) %>% 
  mutate(simpleR = (CLOSE - lagPrice) / lagPrice) %>% 
  mutate(logR = log(CLOSE / lagPrice)) -> priceAAA

# Hiển thị một số kết quả: 

priceAAA %>% 
  select(TICKER, dateYMD, CLOSE, lagPrice, simpleR, logR) %>% 
  head() %>% 
  kbl(caption = "Table 3: Simple và Log Return của mã AAA") %>%
  kable_classic(full_width = FALSE, html_font = "Cambria")
Table 3: Simple và Log Return của mã AAA
TICKER dateYMD CLOSE lagPrice simpleR logR
AAA 2018-01-03 32.95 NA NA NA
AAA 2018-01-08 33.55 32.95 0.0182094 0.0180456
AAA 2018-01-09 33.95 33.55 0.0119225 0.0118520
AAA 2018-01-10 34.00 33.95 0.0014728 0.0014717
AAA 2018-02-05 26.85 34.00 -0.2102941 -0.2360947
AAA 2018-02-06 25.00 26.85 -0.0689013 -0.0713900

Chúng ta có thể tính toán các returns này cho toàn bộ 159 mã (bao gồm cả AAA) chỉ bằng cách kết hợp với hàm dplyr::group_by() như sau:

# Tính toán return cho tất cả 159 mã cổ phiếu: 
priceData %>% 
  group_by(TICKER) %>% 
  mutate(lagPrice = lag(CLOSE, n = 1)) %>% 
  mutate(simpleR = (CLOSE - lagPrice) / lagPrice) %>% 
  mutate(logR = log(CLOSE / lagPrice)) -> priceData

Và đương nhiên chúng ta có thể xem qua dữ liệu của bất kì mã nào. Chẳng hạn cho mã FLC:

priceData %>% 
  filter(TICKER == "FLC") -> priceFLC

priceFLC %>% 
  select(TICKER, dateYMD, CLOSE, lagPrice, simpleR, logR) %>% 
  head() %>% 
  kbl() %>%
  kable_classic(full_width = FALSE, html_font = "Cambria")
TICKER dateYMD CLOSE lagPrice simpleR logR
FLC 2018-01-03 6.80 NA NA NA
FLC 2018-01-04 6.83 6.80 0.0044118 0.0044021
FLC 2018-01-08 6.79 6.83 -0.0058565 -0.0058737
FLC 2018-01-09 6.90 6.79 0.0162003 0.0160705
FLC 2018-01-10 7.03 6.90 0.0188406 0.0186653
FLC 2018-02-05 5.66 7.03 -0.1948791 -0.2167628

3. Các đặc điểm thống kê của Return

Khi phân tích return của cổ phiếu, các nhà đầu tư và nhà phân tích thường sử dụng các thước đo thống kê như Mean (trung bình), Standard Deviation (độ lệch chuẩn), Skew (độ lệch) và Kurtosis (độ nhọn) để đánh giá hiệu suất và rủi ro. Các thước đo này cung cấp cho nhà đầu tư cũng như nhà quản trị danh mục đầu tư về mức độ rủi ro và phần thưởng của việc đầu tư vào một tài sản tài chính bấn kì.

Mean (Trung Bình) là return kỳ vọng từ khoản đầu tư trong một khoảng thời gian nhất định. Theo Bodie, Kane và Marcus (2014), mean là một chỉ số quan trọng giúp so sánh hiệu suất giữa các cổ phiếu khác nhau và xác định mức sinh lời trung bình và được tính theo công thức sau:

\[{Mean} = \frac{1}{N} \sum_{i=1}^{N} R_i\]

Standard Deviation (Độ Lệch Chuẩn, kí hiệu \(\sigma\)) đo lường mức độ biến động của return so với mean và được tính theo công thức sau:

\[\sigma = \sqrt{\frac{1}{N-1} \sum_{i=1}^{N} (R_i - \bar{R})^2}\]

Thống kê này cho biết mức độ rủi ro liên quan đến một khoản đầu tư. Độ lệch chuẩn càng cao, mức độ biến động của return càng lớn, và do đó, rủi ro càng cao (Hull, 2015).

Skew (Độ Lệch) phản ánh sự bất đối xứng của phân phối return xung quanh mean. Nếu phân phối có skew dương, phần đuôi bên phải của phân phối dài hơn phần đuôi bên trái, ngược lại, nếu skew âm, phần đuôi bên trái dài hơn. Điều này giúp nhà đầu tư hiểu rõ hơn về xu hướng của return. Theo Brooks (2019), skew giúp phân tích mức độ bất đối xứng và ảnh hưởng của các biến cố bất ngờ đến return của cổ phiếu. Thống kê này được tính như sau:

\[{Skewness} = \frac{N}{(N-1)(N-2)} \sum_{i=1}^{N} \left(\frac{R_i - \bar{R}}{\sigma}\right)^3\]

Kurtosis (Độ Nhọn) đo lường độ nhọn của phân phối return. Kurtosis cao (leptokurtic) cho thấy sự tập trung cao độ của return xung quanh mean và phần đuôi dày, biểu hiện của các biến động lớn không thường xuyên. Kurtosis thấp (platykurtic) ngược lại, biểu hiện của phân phối phẳng hơn với phần đuôi mỏng hơn. Phân tích kurtosis giúp nhà đầu tư nhận diện các rủi ro liên quan đến các sự kiện cực đoan (Campbell, Lo & MacKinlay, 1997). Thống kê này được tính như sau:

\[{Kurtosis} = \frac{N(N+1)}{(N-1)(N-2)(N-3)} \sum_{i=1}^{N} \left(\frac{R_i - \bar{R}}{\sigma}\right)^4 - \frac{3(N-1)^2}{(N-2)(N-3)}\]

Hai thống kê đầu chúng ta có thể sử dụng hàm base::mean()base::mean() để tính. Hai thống kê sau chúng ta sử dụng các hàm moments::skewness()moments::kurtosis(). Dưới đây là R codes tính toán bốn thống kê này cho tất cả 159 mã cổ phiếu. Lưu ý rằng chúng ta cần loại bỏ các giá trị NA (Not Available) trước khi tính:

# Tính toán 4 thống kê phổ biến cho 159 mã CP: 

library(moments)

priceData %>% 
  filter(!is.na(lagPrice)) %>% 
  group_by(TICKER) %>% 
  summarise(N = n(), 
            Mean = mean(simpleR), 
            SD = sd(simpleR), 
            Skewness = skewness(simpleR), 
            Kurtosis = kurtosis(simpleR)) -> reportForAll


# Sắp xếp theo chiều giảm dần của mean return và hiểu thị một số: 

reportForAll %>% 
  ungroup() %>% 
  arrange(-Mean) -> reportForAll

reportForAll %>% 
  head() -> top6byMean

top6byMean %>% 
  kbl(caption = "Table 4: Một số đặc điểm thống kê của 6 mã có trung bình Simple Return cao nhất") %>%
  kable_classic(full_width = FALSE, html_font = "Cambria")
Table 4: Một số đặc điểm thống kê của 6 mã có trung bình Simple Return cao nhất
TICKER N Mean SD Skewness Kurtosis
CMX 414 0.0051166 0.0396767 0.1096146 2.509056
FIR 243 0.0045975 0.0186749 2.4309078 8.772849
ACL 414 0.0038525 0.0314772 0.1999437 3.230572
HOT 413 0.0027036 0.0471221 -0.1179022 2.296888
ANV 414 0.0025922 0.0304896 2.9525003 34.467511
CCL 414 0.0021649 0.0299927 0.7815988 6.311123

Tính toán những thống kê này cho Log Return là hoàn toàn tương tự.

4. Mối quan hệ giữa lợi tức kì vọng và rủi ro

Độ lệch chuẩn được sử dụng như một thước đo rủi ro. Thống kê này càng cao cho thấy mức độ không chắc chắn càng lớn về mức lợi tức của cổ phiếu, và do đó rủi ro càng lớn. Trong khi đó lợi tức kì vọng là “phần thưởng” cho việc chấp nhận rủi ro này của nhà đầu tư. Lý thuyết hiện đại về danh mục đầu tư (Modern Portfolio Theory - MPT) của Markowitz (1952) đã chỉ ra rằng nhà đầu tư sẽ tìm kiếm một mức lợi tức kỳ vọng cao hơn để bù đắp cho mức rủi ro cao, biểu hiện qua độ lệch chuẩn cao của cổ phiếu. Điều này hàm ý rằng giữa lợi tức kì vọng và rủi ro có mối quan hệ thuận chiều với nhau. Nói cách khác cổ phiếu có lợi tức càng cao thì rủi ro sẽ càng lớn. Chúng ta có thể kiểm tra mô hình MPT bằng cách xét mô hình hồi quy sau:

\[R_i = \beta_0 + \beta_1 Risk_i + \epsilon_i\]

Trong đó:

  • \(R_i\) là lợi tức kì vọng của tài sản thứ i.
  • \(Risk_i\) là rủi ro tương ứng của tài sản thứ i. Proxy cho rủi ro là độ lệch chuẩn.
  • \(\epsilon_i\) là sai số ngẫu nhiên.

Nếu \(\beta_1\) có giá trị dương và có ý nghĩa thống kê thì điều đó cũng có nghĩa là bằng chứng thực nghiệm từ dữ liệu xác nhận các giả thuyết của MPT. Ước lượng cho các hệ số hồi quy có kết quả được trình bày trong Table 5.

# Ước lượng các hệ số hồi quy: 
reportForAll %>% lm(Mean ~ SD, data = .) -> myOLS

library(stargazer) # Package cho báo cáo kết quả hồi quy. 

# Kết quả hồi quy. 
stargazer(myOLS, 
          title = "Table 5: Compare Panel Data Regression Results",
          type = "text", 
          align = TRUE)
## 
## Table 5: Compare Panel Data Regression Results
## ===============================================
##                         Dependent variable:    
##                     ---------------------------
##                                Mean            
## -----------------------------------------------
## SD                             0.018           
##                               (0.014)          
##                                                
## Constant                     -0.001**          
##                              (0.0004)          
##                                                
## -----------------------------------------------
## Observations                    159            
## R2                             0.010           
## Adjusted R2                    0.004           
## Residual Std. Error      0.001 (df = 157)      
## F Statistic             1.555 (df = 1; 157)    
## ===============================================
## Note:               *p<0.1; **p<0.05; ***p<0.01

Hệ số \(\beta_1 = 0.018\) là dương cho thấy giữa lợi tức kì vọng và rủi ro có quan hệ thuận chiều như tuyên bố của lí thuyết MPT. Tuy nhiên kết luận này không có ý nghĩa thống kê. Chúng ta có thể hình ảnh hóa quan hệ này giữa lợi tức kì vọng và rủi ro bằng Scatter Plot (Figure 2) như sau:

reportForAll %>% 
  ggplot(aes(y = Mean, x = SD)) + 
  geom_point(alpha = 0.4) + 
  geom_smooth(method = "lm", se = FALSE) + 
  labs(title = "Figure 2: Mối quan hệ giữa lợi tức kì vọng và rủi ro", 
       subtitle = "Note: Proxy cho rủi ro là độ lệch chuẩn", 
       caption = "Source: https://bvsc.com.vn")

5. Phân tích và quản trị danh mục đầu tư với tidyquant

Thư viện tidyquant kết hợp khả năng phân tích tài chính của các gói như quantmod, PerformanceAnalytics, và TTR với các thư viện xử lý và trực quan hóa dữ liệu của hệ sinh thái tidyverse (Peterson & Carl, 2020; Kassambara, 2021; Wickham et al., 2019). Thư viện này cung cấp một giao diện thuận tiện để lấy và xử lý dữ liệu tài chính, giúp các nhà phân tích cũng như các nhà quản trị danh mục, quản trị rủi ro dễ dàng thực hiện các phân tích định lượng phức tạp (Silge & Robinson, 2017; Grolemund & Wickham, 2017).

Hàm tidyquant::tq_get() của thư viện này có thể lấy dữ liệu từ các nguồn dưới đây (và không chỉ là những dữ liệu tài chính truyền thống):

  • Yahoo Finance: Daily stock data.
  • FRED: Economic data.
  • Quandl: Economic, Energy, & Financial Data API.
  • Tiingo: Financial API with sub-daily stock data and crypto-currency.
  • Alpha Vantage Financial API with sub-daily, ForEx, and crypto-currency data.
  • Bloomberg: Financial API (cần trả phí).

Chúng ta có thể lấy dữ liệu cho một hoặc nhiều mã cổ phiếu cùng một lúc trong khoảng thời gian bất kì. Dưới đây là ví dụ về lấy dữ liệu cho Microsoft (mã MSFT), Goldman Sachs (Mã GS), American Express (mã AXP) và McDonald’s (mã MCD) từ 2000-01-01 đến 2023-12-31:

# Load tidyquant: 
library(tidyquant)

# Danh sách các mã cổ phiếu cần lấy dữ liệu: 

mySymbols <- c("MSFT", "GS", "AXP", "MCD")

# Lấy dữ liệu giao dịch của hai mã cổ phiếu này: 

tq_get(x = mySymbols, 
       get = "stock.prices",
       from = "2000-01-01", 
       to = "2023-12-31") -> someSymbolsData

# Xem qua dữ liệu: 

someSymbolsData %>% 
  group_by(symbol) %>% 
  slice(1:3) %>% 
  kbl(caption = "Table 6: Một phần dữ liệu giao dịch cho GS và MSTF") %>%
  kable_classic(full_width = FALSE, html_font = "Cambria")
Table 6: Một phần dữ liệu giao dịch cho GS và MSTF
symbol date open high low close volume adjusted
AXP 2000-01-03 47.99562 47.99562 45.51560 45.88031 6471267 32.75716
AXP 2000-01-04 45.31501 45.47913 43.50970 44.14795 10440877 31.52032
AXP 2000-01-05 43.91088 44.67677 42.96264 42.96264 8646293 30.71972
GS 2000-01-03 94.18750 94.37500 87.75000 88.31250 1822600 63.29415
GS 2000-01-04 87.00000 87.50000 82.25000 82.75000 1647700 59.30747
GS 2000-01-05 80.87500 81.87500 78.37500 78.87500 1516600 56.53025
MCD 2000-01-03 39.93750 40.06250 38.93750 39.62500 4520600 21.78774
MCD 2000-01-04 39.31250 39.56250 38.37500 38.81250 4216500 21.34098
MCD 2000-01-05 38.81250 40.37500 38.81250 39.43750 5231600 21.68465
MSFT 2000-01-03 58.68750 59.31250 56.00000 58.28125 53228400 36.00063
MSFT 2000-01-04 56.78125 58.56250 56.12500 56.31250 54119000 34.78453
MSFT 2000-01-05 55.56250 58.18750 54.68750 56.90625 64059600 35.15131

Và hoàn toàn tương tự chúng ta có thể xem xu hướng giá đóng cửa của MSFT:

# Line Plot for MSFT: 

someSymbolsData %>% 
  filter(symbol == "MSFT") %>% 
  ggplot(aes(x = date, y = close)) + 
  geom_line() + 
  labs(title = "Figure 3: Giá đóng cửa của mã MSFT từ 2000 đến 2023", 
       subtitle = "Note: Đơn vị tính là USD", 
       caption = "Source: https://finance.yahoo.com")

Moving Average Convergence Divergence (MACD) là một chỉ báo kỹ thuật được sử dụng trong phân tích tài chính để xác định các thay đổi về xu hướng trong giá của một tài sản. Chỉ báo này được phát triển bởi Gerald Appel vào cuối những năm 1970 và bao gồm hai đường trung bình động: đường MACD (được tính bằng cách trừ đi đường trung bình động hàm mũ 26 ngày khỏi đường trung bình động hàm mũ 12 ngày) và đường tín hiệu (đường trung bình động hàm mũ 9 ngày của MACD) (Appel, 2005). MACD được sử dụng rộng rãi vì khả năng dự đoán các tín hiệu mua và bán khi các đường MACD và đường tín hiệu cắt nhau. Khi đường MACD cắt lên trên đường tín hiệu, nó được coi là tín hiệu mua, và ngược lại, khi đường MACD cắt xuống dưới đường tín hiệu, nó được coi là tín hiệu bán (Murphy, 1999). Ngoài ra, biểu đồ histogram của MACD, biểu thị sự chênh lệch giữa MACD và đường tín hiệu, cũng cung cấp thông tin quan trọng về xu hướng giá và động lực thị trường (Pring, 2002).

Chúng ta có thể tính toán MACD từ ngày 2022-01-01 và hình ảnh hóa chỉ số này như sau:

# Tính MACD cho 4 mã cổ phiếu: 

someSymbolsData %>% 
  filter(date >= ymd("2022-01-01")) %>% 
  group_by(symbol) %>%
  tq_mutate(select = close, 
            mutate_fun = MACD, 
            nFast = 12, 
            nSlow = 26, 
            nSig = 9, 
            maType = SMA) %>%
    mutate(diff = macd - signal) -> macd_data

# Hình ảnh hóa MACD: 
macd_data %>% 
    ggplot(aes(x = date)) + 
    geom_hline(yintercept = 0) +
    geom_line(aes(y = macd, col = symbol), show.legend = FALSE) +
    geom_line(aes(y = signal), color = "blue", linetype = 2) +
    geom_bar(aes(y = diff), stat = "identity") +
    facet_wrap(~ symbol, ncol = 2, scale = "free") +
    theme_tq() +
    scale_color_tq() + 
    labs(title = "Figure 4: MACD Plot", y = "MACD") 

Hoàn toàn tương tự chúng ta có thể tính toán và hiển thị MACD cho 6 cổ phiếu có lợi tức kì vọng lớn nhất trong khoảng thời gian khảo sát là ACL, ANV, CCL, CMX, FIR và HOT:

priceData %>% 
  filter(TICKER %in% top6byMean$TICKER) -> priceDataTop6

priceDataTop6 %>% 
    group_by(TICKER) %>%
    tq_mutate(select = CLOSE, 
              mutate_fun = MACD, 
              nFast = 12, 
              nSlow = 26, 
              nSig = 9, 
              maType = SMA) %>%
    mutate(diff = macd - signal) %>% 
    ggplot(aes(x = dateYMD)) + 
    geom_hline(yintercept = 0) +
    geom_line(aes(y = macd, col = TICKER), show.legend = FALSE) +
    geom_line(aes(y = signal), color = "blue", linetype = 2) +
    geom_bar(aes(y = diff), stat = "identity") +
    facet_wrap(~ TICKER, ncol = 2, scale = "free") +
    theme_tq() +
    scale_color_tq() + 
    labs(title = "Figure 6: MACD Plot", y = "MACD") 

Hàm tidyquant::tq_transmute() cho phép thực hiện nhiều tính toán quan trọng. Chúng ta có thể tính toán Log Return theo một cách thức khác như sau:

# Tính toán Log Return: 

priceDataTop6 %>% 
    group_by(TICKER) %>%
    tq_transmute(select = CLOSE, 
                 mutate_fun = periodReturn, 
                 period = "daily", 
                 type = "log",
                 col_rename = "logR") -> top6_daily_logReturn

Với dữ liệu đã có chúng ta có thể vẽ Histogram cho Log Return:

top6_daily_logReturn %>% 
    ggplot(aes(x = logR, fill = TICKER)) +
    geom_density(alpha = 0.5, show.legend = FALSE) +
    theme_tq() +
    scale_fill_tq() + 
    facet_wrap(~ TICKER, ncol = 2, scales = "free") + 
    labs(title = "Figure 7: Histogram of Daily Log Returns",
         x = "Monthly Returns", y = "Density")

6. Các Chart thường được sử dụng trong phân tích

Ngoài Line Chart ở trên thì một số dạng chart sau cũng thường được sử dụng cùng R codes tương ứng.

Bar Chart

Biểu đồ thanh (Bar Chart) là một kiểu chart phổ biến trong phân tích kỹ thuật chứng khoán. Mỗi thanh đại diện cho giá mở cửa, cao nhất, thấp nhất và đóng cửa của cổ phiếu trong một khoảng thời gian nhất định. Kiểu biểu đồ thanh giúp nhà đầu tư nhận diện xu hướng, phân tích biến động giá, và dự đoán tương lai. Dưới đây là R codes cho kiểu chart này:

priceAAA %>% 
    ggplot(aes(x = dateYMD, y = CLOSE)) +
    geom_barchart(aes(open = OPEN, high = HIGH, low = LOW, close = CLOSE)) +
    theme_tq() + 
    labs(title = "Figure 8: AAA Bar Chart", 
         subtitle = "Note: Đơn vị tính là USD", 
         y = "Giá đóng cửa", 
         x = "")  

Candlestick Chart

Biểu đồ nến (Candlestick Chart) là công cụ quan trọng trong phân tích kỹ thuật cổ phiếu. Mỗi nến thể hiện giá mở cửa, cao nhất, thấp nhất và đóng cửa trong một phiên giao dịch. Biểu đồ nến giúp các nhà đầu tư nhận diện các mẫu hình giá, xác định xu hướng và dự đoán biến động giá tương lai.

priceAAA %>%
    ggplot(aes(x = dateYMD, y = CLOSE)) +
    geom_candlestick(aes(open = OPEN, high = HIGH, low = LOW, close = CLOSE)) +
    theme_tq() + 
    labs(title = "Figure 9: AAA Candlestick Chart", 
         subtitle = "Note: Đơn vị tính là USD", 
         y = "Closing Price", 
         x = "")

Chúng ta có thể phóng to một khu vực để nhìn rõ hơn như sau:

aaa_range_60_tbl <- priceAAA %>%
  tail(60) %>%
  summarise(max_high = max(HIGH), min_low  = min(LOW))

priceAAA$dateYMD %>% max() -> end # Ngày cuối cùng. 

priceAAA %>%
    ggplot(aes(x = dateYMD, y = CLOSE)) +
    geom_candlestick(aes(open = OPEN, high = HIGH, low = LOW, close = CLOSE)) +
    theme_tq() + 
    coord_x_date(xlim = c(end - weeks(6), end), c(aaa_range_60_tbl$min_low, aaa_range_60_tbl$max_high)) + 
    labs(title = "Figure 10: AAA Candlestick Chart Zoomed", 
         subtitle = "Note: Đơn vị tính là USD", 
         y = "Closing Price", 
         x = "") 

Candlestick Chart cho nhiều cổ phiếu:

start <- end - weeks(6)

priceDataTop6 %>%
    filter(dateYMD >= start - days(2 * 15)) %>%
    ggplot(aes(x = dateYMD, y = CLOSE, group = TICKER)) +
    geom_candlestick(aes(open = OPEN, high = HIGH, low = LOW, close = CLOSE)) + 
    coord_x_date(xlim = c(start, end)) +
    facet_wrap(~ TICKER, ncol = 2, scale = "free_y") + 
    theme_tq() + 
    labs(title = "Figure 11: Mulitple Stocks Candlestick Chart Zoomed", 
         subtitle = "Note: Đơn vị tính là USD", 
         y = "Closing Price", 
         x = "")

Simple moving averages (SMA)

Đường trung bình đơn giản (Simple Moving Average - SMA là công cụ phân tích kỹ thuật quan trọng. SMA tính giá trung bình của cổ phiếu trong một khoảng thời gian cố định, làm mượt biến động giá ngắn hạn. Nhà đầu tư sử dụng SMA để xác định xu hướng và điểm mua bán hợp lý.

priceAAA %>%
    ggplot(aes(x = dateYMD, y = CLOSE)) +
    geom_candlestick(aes(open = OPEN, high = HIGH, low = LOW, close = CLOSE)) +
    geom_ma(ma_fun = SMA, n = 50, linetype = 5, size = 1.25) +
    geom_ma(ma_fun = SMA, n = 200, color = "red", size = 1.25) + 
    coord_x_date(xlim = c(end - weeks(24), end), 
                 c(aaa_range_60_tbl$min_low * 0.9, aaa_range_60_tbl$max_high)) + 
    theme_tq() + 
    labs(title = "Figure 12: AAA Candlestick Chart, 50 and 200-Day SMA", 
         subtitle = "Note: Đơn vị tính là USD", 
         y = "Closing Price", 
         x = "")

Exponential moving averages (EMA)

Tương tự là đường trung bình lũy thừa (Exponential Moving Average - EMA). EMA đặt trọng số lớn hơn vào các giá gần đây, phản ứng nhanh hơn với biến động giá so với SMA. Nhà đầu tư sử dụng EMA để xác định xu hướng, tín hiệu mua bán và điểm đảo chiều thị trường.

priceAAA %>%
    ggplot(aes(x = dateYMD, y = CLOSE)) +
    geom_candlestick(aes(open = OPEN, high = HIGH, low = LOW, close = CLOSE)) +
    geom_ma(ma_fun = EMA, n = 50, linetype = 5, size = 1.25) +
    geom_ma(ma_fun = EMA, n = 200, color = "red", size = 1.25) + 
    coord_x_date(xlim = c(end - weeks(24), end), 
                 c(aaa_range_60_tbl$min_low * 0.9, aaa_range_60_tbl$max_high)) + 
    theme_tq() + 
    labs(title = "Figure 13: AAA Candlestick Chart, 50 and 200-Day EMA", 
         subtitle = "Note: Đơn vị tính là USD", 
         y = "Closing Price", 
         x = "")

Bollinger Bands

Dải Bollinger (Bollinger Bands) là một đường trung bình động và hai dải biên độ trên và dưới, cách nhau bằng độ lệch chuẩn. Kiểu chart này giúp nhà đầu tư nhận biết biến động giá, mức quá mua, quá bán và xác định điểm vào, ra thị trường. Bollinger Band cho cổ phiếu của AAA:

priceAAA %>%
    ggplot(aes(x = dateYMD, y = CLOSE, open = OPEN, high = HIGH, low = LOW, close = CLOSE)) +  
    geom_candlestick() + 
    geom_bbands(ma_fun = SMA, sd = 2, n = 20) +
    coord_x_date(xlim = c(end - weeks(24), end),
                 ylim = c(aaa_range_60_tbl$min_low * 0.85, 
                          aaa_range_60_tbl$max_high) * 1.05) + 
    theme_tq() + 
    labs(title = "Figure 13: AAA Candlestick Chart, BBands with SMA", 
         subtitle = "Note: Đơn vị tính là USD", 
         y = "Closing Price", 
         x = "")

Bollinger Band cho nhiều cổ phiếu.

start <- end - weeks(24)

priceDataTop6 %>%
    ggplot(aes(x = dateYMD, y = CLOSE, open = OPEN, high = HIGH, low = LOW, close = CLOSE, group = TICKER)) +  
    geom_candlestick() + 
    geom_bbands(ma_fun = SMA, sd = 2, n = 20) +
    coord_x_date(xlim = c(start, end)) +  
    facet_wrap(~ TICKER, ncol = 2, scale = "free_y") + 
    theme_tq() + 
    labs(title = "Figure 14: Candlestick Chart for 6 Symbols, BBands with SMA", 
         subtitle = "Note: Đơn vị tính là USD", 
         y = "Closing Price", 
         x = "")

Ngoài chứng năng lấy dữ liệu, thực hiện các phân tích định lượng cho từng cổ phiếu hay một nhóm cổ phiếu, thư viện này cũng có thể được sử dụng cho phân tích và quản trị danh mục đầu tư. Chúng ta sẽ trở lại thư viện này ở các chương sau.

Tài liệu tham khảo

  1. Appel, G. (2005). Technical Analysis: Power Tools for Active Investors. FT Press.
  2. Bodie, Z., Kane, A., & Marcus, A. J. (2014). Investments. 10th ed. McGraw-Hill Education.
  3. Brooks, C. (2019). Introductory Econometrics for Finance. 4th ed. Cambridge University Press.”,
  4. Campbell, J. Y., Lo, A. W., & MacKinlay, A. C. (1997). The Econometrics of Financial Markets. Princeton University Press.
  5. Damodaran, A. (2016). Investment Valuation: Tools and Techniques for Determining the Value of Any Asset. John Wiley & Sons.
  6. Fabozzi, F. J. (2013). Encyclopedia of Financial Models. Vol. 1. John Wiley & Sons.
  7. Fama, E.F. and French, K.R. (2015). ‘A five-factor asset pricing model’, Journal of Financial Economics, vol. 116, no. 1, pp. 1-22.
  8. Grolemund, G., & Wickham, H. (2017). R for Data Science: Import, Tidy, Transform, Visualize, and Model Data. O’Reilly Media.
  9. Hull, J. C. (2015). Options, Futures, and Other Derivatives. 9th ed. Pearson.
  10. Markowitz, H.M. (1952). ‘Portfolio Selection’. The Journal of Finance, 7(1), 77-91.
  11. Peterson, B. G., & Carl, P. (2020). PerformanceAnalytics: Econometric Tools for Performance and Risk Analysis. R package version 2.0.4.
  12. Pring, M. J. (2002). Technical Analysis Explained: The Successful Investor’s Guide to Spotting Investment Trends and Turning Points. McGraw-Hill.
  13. Ross, S.A., Westerfield, R.W., and Jordan, B.D. (2019). Fundamentals of Corporate Finance. McGraw-Hill Education.
  14. Wickham, H., François, R., Henry, L., & Müller, K. (2019). dplyr: A Grammar of Data Manipulation. R package version 0.8.3.