VNDS là một package đầu tiên trên R cho phép bạn lấy dữ liệu giá chứng khoán của tất cả các mã niêm yết trên sàn HNX, HOSE, UPCOM của thị trường chứng khoán Việt Nam. Mục đích của package này là cung cấp một công cụ khai thác dữ liệu chứng khoán cho những nhà phân tích tài chính bằng ngôn ngữ R bao gồm giá cả, thông tin tài chính và hoạt động kinh doanh của các công ty. Và không chỉ dừng ở đó, package hướng tới việc cung cấp các biểu đồ phân tích, thống kê mô tả về phân phối, lợi tức của chứng khoán và đưa ra các mô hình tối ưu hóa danh mục, mô hình rủi ro thị trường.
library(VNDS)
#2.Lấy bảng cân đối kế toán
#Cho 5 năm tài chính gần nhất kể từ 2017
(VNDBalanceSheet <- tq_balancesheet(symbol = "VND",
endYear = 2017,
n = 5,
period = "IN_YEAR"))
#Cho 5 quí gần nhất kể từ Q4/2017
VNDBalanceSheet <- tq_balancesheet(symbol = "VND",
endYear = 2017,
n = 5,
period = "Q4")
#3.Lấy báo cáo hoạt động kinh doanh
#Tương tự như getBalanceSheetReport
(VNDBusinessReport <- tq_business_report(symbol = "VND",
endYear = 2017,
n = 5,
period = "Q1"))
VNDBusinessReport <- tq_business_report(symbol = "VND",
endYear = 2017,
n = 5,
period = "IN_YEAR")
VNDS cho phép khai thác các thông tin về giá của các nguồn như Vndirect và Cophieu68 thông qua các lệnh tq_get(), tq_get_vnd(), tq_get_cp68(). Kết quả trả về là một định dạng data.frame chứa các trường dữ liệu thuộc class OHLCV của quantmod.
tq_get(symbol, from, to, src = 'VND', minimal = TRUE,...)
tq_get_vnd(symbol, from, to, src = 'VND', minimal = TRUE,...)
tq_get_cp68(symbol, from, to, src = 'VND', minimal = TRUE,...)
symbol: Định dạng character, là mã chứng khoán cần lấy.
from: Định dạng character dạng yyyy-mm-dd, là ngày bắt đầu lấy giá.
end: Định dạng character dạng yyyy-mm-dd, là ngày kết thúc lấy giá.
src: Nguồn cần lấy, có 2 lựa chọn gồm ‘VND’ và ‘CP68’ minimal: Giá trị logical mặc định là TRUE (lấy toàn bộ trường). Nếu FALSE sẽ chỉ lấy OLHCV.
#lấy giá chứng khoán full các trường
(VND <- tq_get(symbol = "VND",
from = "2017-01-01",
to = "2018-01-01",
src = "VND",
minimal = FALSE))
## #VND from 2017-01-01 to 2018-01-01 already cloned
#chỉ lấy các trường chính là OLHCV
(VND <- tq_get(symbol = "VND",
from = "2017-01-01",
to = "2018-01-01",
src = "VND",
minimal = TRUE))
## Note: no visible binding for global variable '.'
## #VND from 2017-01-01 to 2018-01-01 already cloned
#Có thể bỏ minimal vì mặc định là TRUE
sử đụng các lệnh tq_candlechart(),tq_candlechart_symbol(), tq_candlechart_ohlc() để vẽ các biểu đồ nến của các chứng khoán này. tq_candlechart_symbol() sẽ lấy trực tiếp dữ liệu chứng khoán từ internet và vẽ đồ thị thông qua việc truyền tên mã. tq_candlechart_ohlc() sẽ trả về đồ thị từ một OHLC object. tq_candlechart() là kết hợp của 2 hàm trên, có thể tự nhận biết được df_symbol là mã chứng khoán hay OHLC object để vẽ đồ thị.
tq_candlechart(df_symbol, from, to, show.volume = TRUE,
colour=c('#17BECF','#7F7F7F'),title="",...)
tq_candlechart_symbol(symbol, from, to, src = 'VND', minimal = TRUE,colour=c('#17BECF','#7F7F7F'),title=""...)
tq_candlechart_ohlc(df_ohlc,colour=c('#17BECF','#7F7F7F'),title="")
df_symbol: Có thể là một OHLC object (là một dataframe chứa các trường open, high, low, close) hoặc character tên mã chứng khoán.
df_ohlc: Là định dạng của một OHLC object.
symbol: Định dạng character, là mã chứng khoán cần lấy.
from: Định dạng character dạng yyyy-mm-dd, là ngày bắt đầu lấy giá.
end: Định dạng character dạng yyyy-mm-dd, là ngày kết thúc lấy giá.
colour: Định dạng vector độ dài 2L qui định màu sắc của nến tăng, giảm. Mặc định là cặp màu colour=c(‘#17BECF’,‘#7F7F7F’)
title: Tiêu đề của đồ thị. Mặc định là tên oHLC object hoặc mã symbol kết hợp với start_date và end_date.
show.volume: TRUE (giá trị mặc định) sẽ show khối lượng bên dưới. FALSE sẽ không show khối lượng.
library(VNDS)
library(quantmod)
#Vẽ biểu đồ từ một OLCH object.
VND <- tq_get('VND','2017-01-01','2018-01-01')
## #VND from 2017-01-01 to 2018-01-01 already cloned
tq_candlechart_ohlc(VND)
## Note: no visible binding for global variable '.I'
## Note: no visible binding for global variable '.I'
## Note: no visible binding for global variable '.I'
## Note: no visible binding for global variable '.I'
## Note: no visible binding for global variable '.N'
## Note: no visible binding for global variable '.N'
#Vẽ biểu đồ trực tiếp từ symbol truyền vào
tq_candlechart_symbol('VND','2017-01-01','2018-01-01')
## #VND from 2017-01-01 to 2018-01-01 already cloned
#Tự động xác định tham số truyền vào là symbol hay OLCH object để visualize
tq_candlechart(VND)
tq_candlechart('VND','2017-01-01','2018-01-01')
## #VND from 2017-01-01 to 2018-01-01 already cloned
#Thay đổi màu nến tăng giảm
tq_candlechart('VND','2017-01-01','2018-01-01', colour = c('red','darkred'))
## #VND from 2017-01-01 to 2018-01-01 already cloned
Bên cạnh các hàm đặc trưng của thị trường chứng khoán Việt Nam, VNDS hướng tới việc kế thừa các hàm phân tích của package tidyquant của hệ sinh thái tidyverse bởi 3 lý do chính:
tidyquant đã kế thừa lại hầu hết các hàm trong nhóm package của hệ sinh thái QFA (quantitative financial analytics package) như xts, zoo, quantmod, TTR và PerformanceAnalytics. Do đó thay vì kế thừa nhiều package rời rạc thì việc kế thừa theo tidyquant sẽ cover được nhiều chức năng phân tích hơn.
Đặc thù của hệ sinh thái tidyverse là làm việc với các tible object trong khi QFA là xts object và tible object là một định dạng trùng hợp với VNDS package đang sử dụng.
Bên cạnh kế sử dụng các hàm phân tích của QFA, kế thừa theo tidyquant sẽ tận dụng được một hệ sinh thái rộng lớn của tidyverse bao gồm các phương thức data wrangling của dplyr, visualizatioin của ggplot2 và rất nhiều các package khác đang ngày một phình to của hệ sinh thái này:
library(tidyquant)
# Các hàm của hệ sinh thái QFA được kế thừa trong tidyquant
tq_transmute_fun_options()
## $zoo
## [1] "rollapply" "rollapplyr" "rollmax"
## [4] "rollmax.default" "rollmaxr" "rollmean"
## [7] "rollmean.default" "rollmeanr" "rollmedian"
## [10] "rollmedian.default" "rollmedianr" "rollsum"
## [13] "rollsum.default" "rollsumr"
##
## $xts
## [1] "apply.daily" "apply.monthly" "apply.quarterly"
## [4] "apply.weekly" "apply.yearly" "diff.xts"
## [7] "lag.xts" "period.apply" "period.max"
## [10] "period.min" "period.prod" "period.sum"
## [13] "periodicity" "to.daily" "to.hourly"
## [16] "to.minutes" "to.minutes10" "to.minutes15"
## [19] "to.minutes3" "to.minutes30" "to.minutes5"
## [22] "to.monthly" "to.period" "to.quarterly"
## [25] "to.weekly" "to.yearly" "to_period"
##
## $quantmod
## [1] "allReturns" "annualReturn" "ClCl"
## [4] "dailyReturn" "Delt" "HiCl"
## [7] "Lag" "LoCl" "LoHi"
## [10] "monthlyReturn" "Next" "OpCl"
## [13] "OpHi" "OpLo" "OpOp"
## [16] "periodReturn" "quarterlyReturn" "seriesAccel"
## [19] "seriesDecel" "seriesDecr" "seriesHi"
## [22] "seriesIncr" "seriesLo" "weeklyReturn"
## [25] "yearlyReturn"
##
## $TTR
## [1] "adjRatios" "ADX" "ALMA"
## [4] "aroon" "ATR" "BBands"
## [7] "CCI" "chaikinAD" "chaikinVolatility"
## [10] "CLV" "CMF" "CMO"
## [13] "DEMA" "DonchianChannel" "DPO"
## [16] "DVI" "EMA" "EMV"
## [19] "EVWMA" "GMMA" "growth"
## [22] "HMA" "KST" "lags"
## [25] "MACD" "MFI" "momentum"
## [28] "OBV" "PBands" "ROC"
## [31] "rollSFM" "RSI" "runCor"
## [34] "runCov" "runMAD" "runMax"
## [37] "runMean" "runMedian" "runMin"
## [40] "runPercentRank" "runSD" "runSum"
## [43] "runVar" "SAR" "SMA"
## [46] "SMI" "SNR" "stoch"
## [49] "TDI" "TRIX" "ultimateOscillator"
## [52] "VHF" "VMA" "volatility"
## [55] "VWAP" "VWMA" "wilderSum"
## [58] "williamsAD" "WMA" "WPR"
## [61] "ZigZag" "ZLEMA"
##
## $PerformanceAnalytics
## [1] "Return.annualized" "Return.annualized.excess"
## [3] "Return.clean" "Return.cumulative"
## [5] "Return.excess" "Return.Geltner"
## [7] "zerofill"
Các hàm chính của tidyquant gồm tq_mutate() và tq_transmute(). Tư tưởng của các hàm này giống với hàm mutate() và transmute() của dplyr (chương I link http://rpubs.com/phamdinhkhanh/381066). Trong đó:
tq_mutate: Tạo trường mới vào bảng sẵn có theo công thức được ta tự định nghĩa. *tq_transmute**: Tạo thêm trường mới vào bảng sẵn có theo công thức được ta tự định nghĩa và drop các trường cũ trong bảng.
tq_mutate(data, select = NULL, mutate_fun, col_rename = NULL,
ohlc_fun = NULL, ...)
tq_mutate_(data, select = NULL, mutate_fun, col_rename = NULL, ...)
tq_mutate_xy(data, x, y = NULL, mutate_fun, col_rename = NULL, ...)
tq_mutate_xy_(data, x, y = NULL, mutate_fun, col_rename = NULL, ...)
tq_transmute(data, select = NULL, mutate_fun, col_rename = NULL,
ohlc_fun = NULL, ...)
tq_transmute_(data, select = NULL, mutate_fun, col_rename = NULL, ...)
tq_transmute_xy(data, x, y = NULL, mutate_fun, col_rename = NULL, ...)
tq_transmute_xy_(data, x, y = NULL, mutate_fun, col_rename = NULL, ...)
Chú ý các hàm có đuôi là _xy sẽ là những hàm có 2 input. Khi đó tham số input cho mutate_fun phải là x,y chứ không phải là select.
data: Một tibble object, chủ yếu được lấy từ hàm tq_get() (VNDS đã đồng bộ format theo tidyquant hàm này tq_get()).
select: Một hàm tương tự như dplyr::select(). Lựa chọn các chỉ số làm input cho mutate_fun. select có thể là tên trường khi có 1 trường hoặc vector vị trí các trường khi có nhiều trường. Chẳng hạn select = c(2:5) thức là sẽ lựa chọn các trường vị trí 2:5 trong dataframe làm input cho mutate_fun.
mutate_fun: Có thể là bất kì hàm số nào trong quantmod,xts,TTR được list trong danh sách tq_mutate_fun_options().
col_rename: Tên của columns mới được tạo thành từ tq_mutate hoặc tq_transmute.
x,y: Tham số được sử dụng với các hàm có đuôi _xy. Đây là các input của các hàm mutate_fun trong các hàm có 2 biến. Chẳng hạn như EVWMA là chuỗi trung bình trượt của giá theo trọng số volume.
…: Các tham số khác được truyền thêm vào hàm.
Giả sử chúng ta cần phân tích chuỗi moving average trong vòng 15 và 50 ngày để tìm ra xu hướng của chuỗi chứng khoán. Thông thường sẽ sử dụng hàm SMA() từ package TTR.
Đầu tiên ta sẽ cần phải lấy dữ liệu định dạng OHLC object từ VNDS:
library(VNDS)
library(tidyquant)
VND <- VNDS::tq_get('VND','2017-01-01','2018-01-01')
## #VND from 2017-01-01 to 2018-01-01 already cloned
head(VND,10)
Kiểm tra danh sách các hàm của TTR được support trong tidyquant đã bao gồm SMA:
tq_mutate_fun_options()$TTR
## [1] "adjRatios" "ADX" "ALMA"
## [4] "aroon" "ATR" "BBands"
## [7] "CCI" "chaikinAD" "chaikinVolatility"
## [10] "CLV" "CMF" "CMO"
## [13] "DEMA" "DonchianChannel" "DPO"
## [16] "DVI" "EMA" "EMV"
## [19] "EVWMA" "GMMA" "growth"
## [22] "HMA" "KST" "lags"
## [25] "MACD" "MFI" "momentum"
## [28] "OBV" "PBands" "ROC"
## [31] "rollSFM" "RSI" "runCor"
## [34] "runCov" "runMAD" "runMax"
## [37] "runMean" "runMedian" "runMin"
## [40] "runPercentRank" "runSD" "runSum"
## [43] "runVar" "SAR" "SMA"
## [46] "SMI" "SNR" "stoch"
## [49] "TDI" "TRIX" "ultimateOscillator"
## [52] "VHF" "VMA" "volatility"
## [55] "VWAP" "VWMA" "wilderSum"
## [58] "williamsAD" "WMA" "WPR"
## [61] "ZigZag" "ZLEMA"
Chúng ta thấy đã bao gồm SMA ở vị trí thứ 45.
dụng hàm SMA() truyền vào mutate_fun để tính toán moving average cho giá đóng cửa với chu kì là n = 15 ngày. Chúng ta sẽ cần truyền trường cần tính SMA vào select và hàm số cần tính vào SMA. Một điểm đặc biệt là chúng ta sử dụng nhân từ pipe nhưng không cần import dplyr bởi tidyquant gọi sẵn nhân tử này.
VND %>% tq_mutate(select = close,
mutate_fun = SMA,
n = 15) %>% tail(10)
Khi chúng ta muốn moving average cho chuỗi giá điều chỉnh thì chỉ cần đưa vào argument select
VND %>% tq_mutate(select = adjusted,
mutate_fun = SMA,
n = 50 ) %>% tail(15)
Tính chỉ số Bolinger band cho chuỗi close:
VND %>% tq_mutate(select = adjusted,
mutate_fun = BBands,
n = 50 ) %>% tail(15)
tính trung bình trượt có trọng EVWMA theo khối lượng của giá
VND %>% tq_mutate_xy(x=adjusted,y=volume,
mutate_fun = EVWMA,
n = 50, col_rename = 'EVWMA') %>% tail(15)
Tính volatility cho chuỗi close
#Dung lenh help để đọc công thức của volatility
#help("volatility")
#Tính volatility cho 260 phiên, sử dụng phương pháp close.
VND %>% tq_mutate(select = c(5),
#c(5) là vị trí của close trong dataframe, cũng có thế viết select = close
mutate_fun = volatility,
n = 10, calc = "close", N = 260,
col_rename = "Volatility") %>% tail(15)
#Tính volatility cho 260 phiên, sử dụng phương pháp garman.klass. Xem ccoong thức trong #help("volatility") sẽ thấy hàm này sử dụng cả 4 chỉ số ohlc nên phải lựa chọn c(2:5)
VND %>% tq_mutate(select = c(2:5),
#c(5) là vị trí của close trong dataframe
mutate_fun = volatility,
n = 10, calc = "garman.klass", N = 260,
col_rename = "Volatility") %>% tail(15)
#Ngoài ra còn có các phương pháp khác như: parkinson, rogers.satchell, Garman and Klass - Yang and Zhang, Yang and Zhang. Khi mutate_fun cần sử dụng công thức nào thì truyền vị trí vào select.
Tính Bollinger bands của chuỗi close
#Kiểm tra công thức Bollinger bands
#help("BBands")
#Tính bollinger bands với chu kì moving average = 20 và độ rộng standard deviation = 2
VND %>% tq_mutate(select = close,
n = 20,
mutate_fun = BBands) %>% tail(15)
#Danh sách các hàm hỗ trợ:
tq_mutate_fun_options()$xts
## [1] "apply.daily" "apply.monthly" "apply.quarterly"
## [4] "apply.weekly" "apply.yearly" "diff.xts"
## [7] "lag.xts" "period.apply" "period.max"
## [10] "period.min" "period.prod" "period.sum"
## [13] "periodicity" "to.daily" "to.hourly"
## [16] "to.minutes" "to.minutes10" "to.minutes15"
## [19] "to.minutes3" "to.minutes30" "to.minutes5"
## [22] "to.monthly" "to.period" "to.quarterly"
## [25] "to.weekly" "to.yearly" "to_period"
Trong đó chúng ta chia thành 2 nhóm chính:
Period apply function: Áp dụng các hàm thống kê theo time segment
Các hàm này được ứng dụng theo time segment (chẳng hạn như tính max, min, mean, … theo các time segment daily,weekly, monthly, quarterly, yearly).
Cú pháp: apply.daily(x, FUN, …). Trong đó FUN là hàm số áp dụng (min,max,mean,…)
Trường hợp chưa xác định periodic sử dụng hàm: period.apply(x,INDEX,FUN,…). INDEX là điểm endpoints đánh dấu cho vị trí kết thúc chu kì. Chẳng hạn với chuỗi weekly thì INDEX là chuỗi 0,7,14,21,28,… cách nhau 7 ngày (nếu weekly tính cả thứ 7,chủ nhật).
Các lựa chọn sẵn có bao gồm: apply.daily, weekly, monthly, quarterly, yearly.
To-period apply function: Chuyển đổi dữ liệu theo chu kì
Chuyển từ chuỗi có chu kì nhỏ sang các chuỗi có chu kì lớn hơn (ví dụ convert chu kì daily to monthly).
Cú pháp: to.period(x, period = ‘months’, k = 1, indexAt, name = NULL, OHLC = TRUE, …).Argument period xác định chu kì (minutes, hourly,daily, weekly, monthly, quarterly, yearly), argument k xác định step của chi kì trong chuỗi, indexAt là định dạng của index sau khi chuỗi mới được trả về (các options: ‘yearmon’, ‘yearqtr’, ‘firstof’, ‘lastof’, ‘startof’, or ‘endof’ tương ứng với tháng, quí, đầu chu kì, cuối chu kì, thời điểm bắt đầu trong data ứng với chu kì,thời điểm kết thúc trong data ứng với chu kì).
Các lựa chọn gồm to.minutes, hourly, daily, weekly, monthly, quarterly, yearly.
Chú ý quan trọng: Cấu trúc trả về là khác nhau đối với hàm to.period và to.monthly (to.weekly, to.quarterly,…). to.period trả về một ngày trong khi to.months trả về kí tự dạng MMM YYYY. Tốt nhất là sử dụng to.period khi làm việc với time-series thông qua package lubridate.
Ví dụ
#Chuyển chuỗi từ ngày sang tháng
#help('to.monthly')
VND %>% tq_transmute(select = c(2:5),
mutate_fun = to.period,
period = 'months') %>% tail(5)
#Lấy giá trung bình trong tháng
VND %>% tq_transmute(select = c(2:5),
mutate_fun = apply.monthly,
period = 'months',
FUN = mean) %>% tail(5)
#Danh sách các hàm hỗ trợ:
tq_mutate_fun_options()$quantmod
## [1] "allReturns" "annualReturn" "ClCl"
## [4] "dailyReturn" "Delt" "HiCl"
## [7] "Lag" "LoCl" "LoHi"
## [10] "monthlyReturn" "Next" "OpCl"
## [13] "OpHi" "OpLo" "OpOp"
## [16] "periodReturn" "quarterlyReturn" "seriesAccel"
## [19] "seriesDecel" "seriesDecr" "seriesHi"
## [22] "seriesIncr" "seriesLo" "weeklyReturn"
## [25] "yearlyReturn"
Các hàm tăng extract và transfrorm OHLC object
Lớp các hàm tính chênh lệch giá trong phiên: ClCl, HiCl, LoCl, LoHi, OpCl, OpHi, OpLo, OpOp. Chẳng hạn khi sử dụng hàm OpCl(OHLC object) kết quả trả về là tăng trưởng trong ngày = Close/Open - 1.
Lớp các hàm Extract data: Op, Hi, Lo, Cl. Các hàm này sẽ lấy dữ liệu với các cột ứng với Open, High, Low, Close.
TÍnh sai phân (Delt) và trễ (Lag):
Delt: Là sai phân của các chuỗi theo thời gian có thể sử dụng phương pháp chia số học hoặc log. Delt(x1, x2 = NULL, k = 0, type = c(“arithmetic”, “log”))
Lag/Next: Nhân tử trễ/ sớm tương ứng với Lag(x, k = 1) / Next: Next(x, k = 1) (Chúng ta cũng có thể sử dplyr::lag và dplyr::lead)
Period Return:
Trả về lợi suất arithmetic hoặc logarithmic cho các chu kì khác nhau như daily, weekly, monthly, quarterly, and yearly.
Cú pháp: periodReturn(x, period = ‘monthly’, subset = NULL, type = ‘arithmetic’, leading = TRUE, …).
Series Functions:
Trả về mô tả của chuỗi. Các lựa chọn bao gồm increases/decreases, acceleration/deceleration, and hi/low.
Cú pháp: seriesHi(x), seriesIncr(x, thresh = 0, diff. = 1L), seriesAccel(x)
Ví dụ
Tính lợi nhuận theo tháng của VND
#help("periodReturn")
VND %>% tq_transmute(select = close,
mutate_fun = periodReturn,
period = 'monthly',
type = 'log') %>% tail(5)
Tính trễ của VND
VND %>% tq_transmute(select = close,
mutate_fun = Lag,
k = 1) %>% tail(5)
# Nhưng tốt nhất là sử dụng hàm lag của dplyr
VND %>% transmute(Lag.1 = lag(close, n = 1L)) %>% tail(5)
Tính tăng/giảm của chuỗi VND
VND %>% tq_mutate(select = close,
mutate_fun = seriesIncr) %>% tail(5)
# Danh sách cá hàm được hỗ trợ
tq_transmute_fun_options()$PerformanceAnalytics
## [1] "Return.annualized" "Return.annualized.excess"
## [3] "Return.clean" "Return.cumulative"
## [5] "Return.excess" "Return.Geltner"
## [7] "zerofill"
Các hàm của PerformanceAnalytics chủ yếu được sử dụng để tính toán các returns:
Return.annualized: Tính lợi suất theo năm.
Return.annualized.excess: Tính lợi suất theo năm chênh lệch giữa 2 giai đoạn.
Return.clean: Tính return sau khi loại bỏ các outlier khỏi return theo 3 phương pháp chính gồm: none, boudt, geltner
Return.excess: Loại bỏ các risk-free rate từ return của yield returns
zerofill: Replace các giá trị NA bằng zeros.
Ví dụ
Tính lợi suất của VND theo năm
#help("Return.annualized")
VND %>% tq_transmute(
mutate_fun = Return.annualized,
scale = 252,
geometric = FALSE)
## open high low close volume adjusted
## Annualized Return 4737.446 4817.861 4663.998 4744.822 174370927 3660.756
Tính lợi suất của VND theo năm clean 95% outliear
VND %>% tq_transmute(select = close,
mutate_fun = Return.clean,
alpha = 0.05,
method = c("geltner")) %>% tail(5)