Các nhà quản lý quỹ tương hỗ có quyền tự quyết đáng kể trong các quyết định đầu tư giữa các ngày công bố danh mục bắt buộc. Mặc dù khung pháp lý yêu cầu công bố định kỳ các khoản nắm giữ, những hành động được thực hiện giữa các ngày công bố này (ví dụ: giao dịch, định thời điểm thị trường, cho vay chứng khoán và quản lý tiền mặt mang tính chiến lược) phần lớn vẫn không thể quan sát được đối với nhà đầu tư. Những hành động không quan sát được này có thể tác động đáng kể đến hiệu suất quỹ, theo hướng tích cực thông qua hoạt động giao dịch giữa kỳ khéo léo, hoặc theo hướng tiêu cực thông qua chi phí đại diện và hành vi ẩn giấu.
Kacperczyk, Sialm, và Zheng (2008) đã phát triển thước đo Return Gap để nắm bắt tác động tổng hợp của các hành động không quan sát được này lên lợi nhuận của quỹ. Return Gap được định nghĩa là chênh lệch giữa lợi nhuận thực tế mà quỹ báo cáo và lợi nhuận giả định của một danh mục được đầu tư một cách máy móc vào các khoản nắm giữ được công bố gần nhất của quỹ. Viết dưới dạng công thức:
trong đó \(R_{i,t}^{\text{Actual}}\) là lợi nhuận ròng sau chi phí do quỹ \(i\) báo cáo trong tháng \(t\), được điều chỉnh theo chi phí để thu được lợi nhuận gộp, và \(R_{i,t}^{\text{Holdings}}\) là lợi nhuận mua và nắm giữ giả định được tính từ các khoản nắm giữ danh mục được công bố gần nhất.
Return Gap dương cho thấy các hành động không quan sát được của nhà quản lý quỹ (ví dụ: giao dịch giữa kỳ, quản lý tiền mặt hoặc các hoạt động khác) đã tạo thêm giá trị so với việc sao chép thụ động các khoản nắm giữ đã công bố. Ngược lại, Return Gap âm kéo dài gợi ý hoạt động giữa kỳ làm hủy hoại giá trị, có thể do chi phí đại diện, thực thi giao dịch kém hoặc phí ẩn.
36.1 Vì sao Return Gap quan trọng
Return Gap có ý nghĩa kinh tế vì nhiều lý do:
Tính bền vững của hiệu suất: Các quỹ thuộc decile Return Gap cao nhất có xu hướng vượt các quỹ thuộc decile thấp nhất 1-2% mỗi năm trên cơ sở điều chỉnh theo rủi ro, và mức chênh lệch này kéo dài theo thời gian (Kacperczyk, Sialm, và Zheng 2008).
Phát hiện vấn đề đại diện: Return Gap âm kéo dài có thể báo hiệu các chi phí ẩn như giao dịch quá mức, chi phí tác động thị trường, thỏa thuận soft-dollar hoặc khai thác giá lỗi thời.
Bổ sung cho các thước đo truyền thống: Không giống các chỉ số dựa trên alpha vốn trộn lẫn kỹ năng chọn cổ phiếu với kỹ năng giao dịch giữa kỳ, Return Gap tách riêng thành phần hiệu suất quy cho các hành động được thực hiện giữa các ngày công bố.
Hàm ý đối với cơ quan quản lý: Ở các thị trường mới nổi như Việt Nam, nơi tần suất công bố thông tin và sự giám sát của cơ quan quản lý có thể khác với thị trường phát triển, Return Gap có thể đóng vai trò hệ thống cảnh báo sớm cho việc bảo vệ nhà đầu tư.
36.2 Các khoản chi trả ẩn: Chia sẻ doanh thu, phân phối và thiết kế danh mục lựa chọn
Return Gap định lượng hệ quả của những gì nhà quản lý làm giữa các ngày công bố. Một nhánh nghiên cứu bổ sung cho thấy kết quả của nhà đầu tư cũng được định hình ngang bằng bởi các khoản chi trả luân chuyển giữa quỹ và các đơn vị phân phối, phần lớn nằm ngoài tầm nhìn của nhà đầu tư. Pool, Sialm, và Stefanescu (2026) đưa ra bằng chứng rõ ràng nhất từ các kế hoạch 401(k) của Hoa Kỳ, nơi đơn vị quản lý hồ sơ (recordkeeper) quản lý kế hoạch thường được trả công gián tiếp thông qua chia sẻ doanh thu: các khoản hoàn trả do các quỹ tương hỗ bên thứ ba trong danh mục lựa chọn của kế hoạch chi trả từ tỷ lệ chi phí của họ. Những thỏa thuận này làm méo mó chính danh mục lựa chọn: các quỹ chia sẻ doanh thu có nhiều khả năng được thêm vào và ít khả năng bị loại bỏ hơn, và các kế hoạch chia sẻ doanh thu đắt đỏ hơn nói chung, với tỷ lệ chi phí cao hơn không được bù đắp bởi phí trực tiếp thấp hơn hay hiệu suất tốt hơn. Các khoản hoàn trả cũng tăng theo sức mạnh thị trường của đơn vị quản lý hồ sơ, phù hợp với việc các quỹ chia sẻ doanh thu để mua quyền tiếp cận tài sản hưu trí.
Kết quả này mở rộng một nhánh nghiên cứu lâu đời hơn về xung đột phân phối trong quản lý tài sản ủy thác. Pool, Sialm, và Stefanescu (2016) cho thấy các công ty quản lý quỹ tương hỗ đóng vai trò người được ủy thác của các kế hoạch 401(k) ưu ái các quỹ trực thuộc chính họ trong các quyết định về danh mục lựa chọn, đặc biệt là các quỹ hoạt động kém, và người tham gia không đảo ngược sự ưu ái này. Sialm, Starks, và Zhang (2015) thấy rằng dòng vốn của các kế hoạch hưu trí đóng góp xác định phản ứng mạnh với hiệu suất, nhưng phần lớn là do các nhà tài trợ kế hoạch thêm và bớt các lựa chọn trong danh mục, điều này tập trung ảnh hưởng vào chính các trung gian mà chia sẻ doanh thu nhắm tới. Ngoài các kế hoạch hưu trí, Bergstresser, Chalmers, và Tufano (2009) ghi nhận rằng các quỹ bán qua môi giới có hiệu suất kém hơn các quỹ bán trực tiếp ngay cả trước phí phân phối, và Christoffersen, Evans, và Musto (2013) cho thấy các khoản chi trả cho nhà môi giới dự báo dòng vốn vào quỹ và hiệu suất thấp hơn sau đó, cho thấy rằng thù lao của trung gian, chứ không chỉ cầu của nhà đầu tư, dẫn dắt dòng tiền.
Những phát hiện này quan trọng đối với Việt Nam vì ngành quỹ của nước ta do kênh phân phối dẫn dắt: phần lớn tài sản của các quỹ mở được huy động qua ngân hàng, công ty chứng khoán và các nền tảng phân phối quỹ được cấp phép, các chương trình hưu trí bổ sung tự nguyện còn non trẻ, và các thỏa thuận phí giữa nhà quản lý quỹ và đơn vị phân phối không được công bố một cách có hệ thống. Khi các sản phẩm theo kiểu danh mục lựa chọn lan rộng qua các nền tảng quỹ, bảo hiểm gắn với hưu trí và các chương trình tiết kiệm do người sử dụng lao động tài trợ, bằng chứng của Hoa Kỳ gợi ý một chương trình nghiên cứu và quản lý rõ ràng: đo lường không chỉ những gì quỹ báo cáo và nắm giữ, mà còn cả việc ai được trả tiền để có vị trí trên “kệ hàng”, vì những khoản chi trả này dự báo cả thành phần danh mục lựa chọn lẫn chi phí của nhà đầu tư. Phương pháp Return Gap được phát triển trong chương này và các chẩn đoán dựa trên phí bổ trợ cho nhau trong chương trình đó: một bên theo dõi các hành động ẩn, bên kia theo dõi các khoản chi trả ẩn.
36.3 Các đầu vào ẩn: Vốn nhân lực và kỹ năng của quỹ
Điều thứ ba mà nhà đầu tư hiếm khi quan sát được là ai tạo ra hiệu suất của quỹ. Alpha, Return Gap và các thước đo kỹ năng liên quan là các đầu ra; còn đầu vào là các nhà phân tích và nhân sự định lượng mà công ty quản lý tuyển dụng được. Việc xác định đóng góp nhân quả của những đầu vào này rất khó vì những người tài năng tự lựa chọn vào các quỹ vốn đã hoạt động tốt. Chen và c.s. (2026) giải quyết vấn đề lựa chọn bằng một cuộc xổ số. Các công ty quản lý quỹ phòng hộ của Hoa Kỳ nộp đơn xin thị thực lao động tay nghề cao H-1B, và khi số đơn vượt quá hạn ngạch hằng năm, thị thực được phân bổ bằng bốc thăm ngẫu nhiên, nên hai công ty nộp đơn cùng số lượng thị thực nhưng trúng số lượng khác nhau có thể so sánh với nhau ngay từ đầu. Các công ty trúng nhiều thị thực hơn sau đó mang lại alpha, tỷ số Sharpe và tỷ số thông tin cao hơn. Hiệu ứng này được truy về những người lao động được trả lương cao, có trình độ học vấn cao và kỹ năng định lượng, giúp các quỹ phát triển chiến lược riêng biệt, kinh doanh chênh lệch giá các hiện tượng bất thường nổi bật của cổ phiếu và nới lỏng các ràng buộc về quy mô (capacity). Hai kết quả khác làm rõ thêm cách diễn giải: việc cắt giảm bất ngờ hạn ngạch H-1B làm tổn hại hiệu suất của những quỹ phụ thuộc nhiều nhất vào các lao động như vậy, và việc tạo alpha lớn nhất ở những lao động đến từ các quốc gia có thời gian chờ thường trú nhân Hoa Kỳ lâu nhất, phù hợp với việc các quỹ khai thác một ma sát trên thị trường lao động ràng buộc người lao động với đơn vị bảo lãnh.
Thiết kế này có một phiên bản tương tự trực tiếp ở Việt Nam. Các công ty quản lý quỹ ở Việt Nam cạnh tranh nhau để thu hút một nhóm nhỏ các nhà phân tích đạt chứng chỉ CFA và nhân sự được đào tạo về định lượng, các nhà quản lý có liên kết nước ngoài luân chuyển nhân sự nước ngoài ra vào Thành phố Hồ Chí Minh, và các quy định về giấy phép lao động và cấp phép cho chuyên gia nước ngoài thay đổi theo thời gian. Một nhà nghiên cứu có thể quan sát nhân sự ở cấp công ty quản lý, dù từ hồ sơ cấp phép hành nghề quản lý quỹ của UBCKNN (SSC), dữ liệu giấy phép lao động, hay hồ sơ nghề nghiệp kiểu LinkedIn, có thể hỏi liệu các nhân sự có kỹ năng được tuyển có dự báo alpha và Return Gap sau đó hay không, và có thể khai thác các thay đổi quy định về lao động nước ngoài làm cú sốc. Bài học từ Chen và c.s. (2026) là các hành động ẩn và các khoản chi trả ẩn chỉ là một phần của câu chuyện; các đầu vào ẩn cũng quan trọng đối với hiệu suất, và việc phân bổ ngẫu nhiên hoặc gần như ngẫu nhiên các đầu vào này là điều biến mối tương quan giữa tài năng và lợi nhuận thành bằng chứng về kỹ năng.
36.4 Ứng dụng vào thị trường Việt Nam
Ngành quỹ tương hỗ Việt Nam, tuy còn non trẻ so với Hoa Kỳ, đã tăng trưởng nhanh chóng kể từ khi các quỹ cổ phiếu trong nước đầu tiên được thành lập vào đầu những năm 2000. Tính đến năm 2024, ngành quỹ mở của Việt Nam quản lý tài sản vượt 100 nghìn tỷ VND, với hàng chục quỹ thiên về cổ phiếu do các công ty quản lý tài sản trong nước và có liên kết nước ngoài điều hành.
Một số đặc điểm của thị trường Việt Nam khiến phân tích Return Gap đặc biệt thú vị:
Tần suất công bố thông tin: Các quỹ Việt Nam được yêu cầu công bố định kỳ các khoản nắm giữ hàng đầu, nhưng tần suất và mức độ đầy đủ của việc công bố có thể khác với yêu cầu hằng quý của SEC tại Hoa Kỳ.
Vi cấu trúc thị trường: HOSE (Sở Giao dịch Chứng khoán TP. Hồ Chí Minh) và HNX (Sở Giao dịch Chứng khoán Hà Nội) áp dụng biên độ giá hằng ngày (cộng hoặc trừ 7% trên HOSE, cộng hoặc trừ 10% trên HNX), thanh toán T+2 và giới hạn sở hữu nước ngoài, những yếu tố có thể hạn chế hoặc tạo điều kiện cho một số chiến lược giao dịch giữa kỳ.
Bất đối xứng thông tin: Ở thị trường mới nổi có ít phân tích viên theo dõi hơn, phạm vi cho giao dịch giữa kỳ có thông tin và do đó Return Gap dương có thể lớn hơn so với các thị trường hiệu quả hơn.
Môi trường pháp lý: Ủy ban Chứng khoán Nhà nước (SSC) của Việt Nam đã dần tăng cường các yêu cầu về công bố thông tin và quản trị, khiến phân tích Return Gap theo thời gian đặc biệt có giá trị.
37 Khung lý thuyết
37.1 Phân rã lợi nhuận của quỹ
Xét một quỹ tương hỗ \(i\) công bố các khoản nắm giữ danh mục tại các thời điểm rời rạc \(\tau_1, \tau_2, \ldots\) Như được công bố tại thời điểm \(\tau_k\), quỹ nắm giữ \(N_k\) chứng khoán với các tỷ trọng \(\{w_{j,\tau_k}\}_{j=1}^{N_k}\), trong đó \(w_{j,\tau_k}\) biểu thị tỷ trọng danh mục của chứng khoán \(j\).
Giữa các ngày công bố \(\tau_k\) và \(\tau_{k+1}\), lợi nhuận gộp thực tế của quỹ trong tháng \(t\) có thể được phân rã như sau:
Lợi nhuận nắm giữ giả định \(R_{i,t}^{\text{Holdings}}\) được tính là lợi nhuận theo trọng số giá trị của danh mục mua và nắm giữ dựa trên lần công bố gần nhất:
trong đó \(r_{j,t}\) là lợi nhuận của chứng khoán \(j\) trong tháng \(t\), và \(\tilde{w}_{j,t-1}\) là tỷ trọng danh mục đã biến đổi vào cuối tháng \(t-1\), phản ánh sự trôi tỷ trọng do mua và nắm giữ từ các tỷ trọng công bố ban đầu:
Trong thực tế, thay vì theo dõi tường minh các tỷ trọng đã biến đổi, chúng ta dùng giá trị bằng đô la (ở đây là VND) của các vị thế nắm giữ (số cổ phiếu nắm giữ nhân với giá) làm cách gán trọng số tự nhiên.
37.2 Thước đo Return Gap
37.2.1 Return Gap gộp
Return Gap như được Kacperczyk, Sialm, và Zheng (2008) định nghĩa ban đầu sử dụng lợi nhuận gộp (trước chi phí):
trong đó \(R_{i,t}^{\text{Net}}\) là lợi nhuận ròng sau chi phí được báo cáo và tỷ lệ chi phí hằng năm được chia cho 12 để xấp xỉ khoản chi phí hằng tháng.
\(\Delta_{\text{trade}}\): Tác động lên lợi nhuận của việc mua và bán chứng khoán giữa các ngày công bố. Các nhà quản lý có kỹ năng tạo ra \(\Delta_{\text{trade}}\) dương nhờ định thời điểm giao dịch.
\(\Delta_{\text{cash}}\): Hiệu ứng của việc nắm giữ tiền mặt hoặc các khoản tương đương tiền không được phản ánh trong các công bố nắm giữ cổ phiếu. Trong thị trường tăng, tiền mặt tạo ra lực cản (đóng góp âm); trong thị trường giảm, tiền mặt tạo ra lớp đệm.
\(\Delta_{\text{fees}}\): Chi phí giao dịch, hoa hồng môi giới và mọi khoản phí ẩn không phản ánh trong tỷ lệ chi phí công bố.
\(\Delta_{\text{lend}}\): Doanh thu từ các chương trình cho vay chứng khoán, tạo ra Return Gap dương.
\(\varepsilon_t\): Nhiễu đo lường do chênh lệch thời điểm, giá lỗi thời hoặc lỗi dữ liệu.
37.2.3 Return Gap dự báo
Để hình thành các danh mục có thể giao dịch và tránh thiên lệch nhìn trước, Kacperczyk, Sialm, và Zheng (2008) dùng Return Gap trung bình 12 tháng gần nhất, trễ một quý để tính đến độ trễ báo cáo:
Độ trễ bổ sung 3 tháng (một quý) bảo đảm tín hiệu Return Gap chỉ dựa trên thông tin mà nhà đầu tư có được tại thời điểm hình thành danh mục. Điều này đặc biệt quan trọng ở Việt Nam, nơi việc báo cáo của quỹ có thể bị chậm.
37.3 Đánh giá hiệu suất điều chỉnh theo rủi ro
Để đánh giá liệu các danh mục được sắp xếp theo Return Gap có tạo ra lợi nhuận điều chỉnh theo rủi ro thực sự hay không, chúng ta sử dụng một số mô hình nhân tố.
trong đó \(\text{RMW}_t\) (robust minus weak) nắm bắt khả năng sinh lời và \(\text{CMA}_t\) (conservative minus aggressive) nắm bắt các mô thức đầu tư.
37.4 Sai số chuẩn Newey-West
Vì lợi nhuận danh mục có thể có tương quan chuỗi, chúng ta sử dụng sai số chuẩn Newey và West (1987) với \(L\) độ trễ:
và \(\hat{\Gamma}_\ell = \frac{1}{T}\sum_{t=\ell+1}^{T} \hat{\epsilon}_t \hat{\epsilon}_{t-\ell} \mathbf{x}_t \mathbf{x}_{t-\ell}'\). Cách chọn độ trễ tiêu chuẩn là \(L = \lfloor 4(T/100)^{2/9} \rfloor\).
38 Dữ liệu và xây dựng mẫu
38.1 Nguồn dữ liệu
Bảng 38.1 trình bày các nguồn được dùng để xây dựng return gap.
Bảng 38.1: Nguồn dữ liệu cho phân tích Return Gap tại Việt Nam
Nhóm dữ liệu
Nguồn
Mô tả
Các khoản nắm giữ của quỹ
DataCore Fund Holdings
Các vị thế danh mục được công bố gồm mã chứng khoán, số cổ phiếu nắm giữ, ngày báo cáo và ngày phiên bản (nộp hồ sơ)
Lợi nhuận của quỹ
DataCore Fund Performance
Lợi nhuận ròng dựa trên NAV hằng tháng, tổng tài sản ròng và tỷ lệ chi phí
Đặc điểm của quỹ
DataCore Fund Master
Mã mục tiêu của quỹ, ngày thành lập, công ty quản lý, phong cách đầu tư
Giá và lợi nhuận cổ phiếu
DataCore Equity Market
Giá điều chỉnh, lợi nhuận, số cổ phiếu lưu hành và các sự kiện doanh nghiệp hằng ngày và hằng tháng của các chứng khoán niêm yết trên HOSE và HNX
Các nhân tố rủi ro
DataCore / Tự xây dựng
Các danh mục nhân tố thị trường Việt Nam (MKT, SMB, HML, UMD, RMW, CMA)
38.2 Thiết lập môi trường
Import libraries and configure settings
import pandas as pdimport numpy as npimport matplotlib.pyplot as pltimport seaborn as snsimport statsmodels.api as smfrom statsmodels.regression.linear_model import OLSfrom scipy import statsfrom datetime import datetime, timedeltafrom dateutil.relativedelta import relativedeltaimport warningswarnings.filterwarnings("ignore")plt.rcParams.update({"figure.figsize": (10, 6),"font.size": 12,"axes.titlesize": 14,"axes.labelsize": 12,"xtick.labelsize": 10,"ytick.labelsize": 10,"legend.fontsize": 10,"figure.dpi": 150,"savefig.dpi": 300,"font.family": "serif",})sns.set_style("whitegrid")np.random.seed(42)
38.3 Tải và chuẩn bị dữ liệu thị trường chứng khoán
Bước đầu tiên là tải dữ liệu cấp cổ phiếu, vốn là nền tảng để tính lợi nhuận nắm giữ giả định.
39.1 Bước 1: Chuẩn bị các phiên bản dữ liệu nắm giữ
Một bước đầu tiên quan trọng là xử lý đúng cấu trúc phiên bản (vintage) của dữ liệu nắm giữ. Mỗi báo cáo nắm giữ có hai ngày then chốt: ngày báo cáo (\(\tau\), ngày tham chiếu) và ngày nộp hồ sơ (\(f\), khi thông tin được công bố công khai). Chúng ta chỉ giữ phiên bản đầu tiên cho mỗi cặp quỹ–ngày báo cáo.
Process holdings vintages and determine holding periods
Đây là phép tính cốt lõi. Với mỗi quỹ, chúng ta lấy các khoản nắm giữ được công bố tại ngày báo cáo \(\tau\), và với mỗi tháng \(t\) trong \((\tau, \tau_{\text{next}}]\), tính lợi nhuận theo trọng số giá trị, dùng giá trị bằng tiền có độ trễ làm trọng số.
Hình 39.2: Chuỗi thời gian các thống kê chéo của Return Gap. Đường liền: trung vị, vùng tô bóng: khoảng tứ phân vị (IQR), đường nét đứt: trung bình.
40 Phân tích phân loại danh mục
40.1 Hình thành các danh mục decile theo Return Gap
Mỗi tháng \(t\), chúng ta phân loại các quỹ thành các danh mục decile dựa trên Return Gap trung bình 12 tháng có độ trễ của chúng (\(\overline{\text{RG}}_{i,t-4}^{12}\)). Danh mục 1 gồm các quỹ có Return Gap thấp nhất.
46.1 Các đặc điểm thể chế ảnh hưởng đến Return Gap
Một số đặc điểm thể chế của thị trường Việt Nam cần được chú ý đặc biệt khi diễn giải Return Gap:
46.1.1 Giới hạn sở hữu nước ngoài (FOL)
Quy định của Việt Nam áp đặt giới hạn sở hữu nước ngoài đối với các công ty niêm yết (thường là 49% cho hầu hết các ngành, với giới hạn thấp hơn trong ngân hàng và truyền thông). Khi một cổ phiếu tiến sát FOL, nó giao dịch với mức giá cao hơn thông qua các giao dịch “pre-funded”. Một nhà quản lý quỹ dự đoán được các biến động giá do FOL thông qua giao dịch giữa kỳ có thể tạo ra Return Gap dương.
46.1.2 Biên độ giá hằng ngày
HOSE áp dụng biên độ giá hằng ngày cộng hoặc trừ 7%, và HNX cộng hoặc trừ 10%. Các giới hạn này có thể ngăn cản việc khám phá giá đầy đủ trong một ngày, tạo ra cơ hội cho giao dịch giữa kỳ có thông tin trong các kỳ hạn nhiều ngày.
46.1.3 Thanh toán T+2 và giao dịch ký quỹ
Chu kỳ thanh toán T+2 của Việt Nam và khung giao dịch ký quỹ đang phát triển ảnh hưởng đến tốc độ và đòn bẩy mà các nhà quản lý quỹ có thể thực hiện các giao dịch giữa kỳ.
46.1.4 Chuẩn mực công bố thông tin
Chuẩn mực công bố thông tin của quỹ Việt Nam khác với yêu cầu hằng quý tại Hoa Kỳ. UBCKNN (SSC) yêu cầu báo cáo định kỳ, nhưng việc công bố chi tiết đến cấp vị thế có thể ít thường xuyên hơn, làm mở rộng khoảng thời gian cho các hành động không quan sát được.
46.2 So sánh với bằng chứng từ thị trường phát triển
Bảng 46.1 trình bày so sánh giữa thị trường phát triển và thị trường mới nổi.
Bảng 46.1: So sánh bối cảnh Return Gap giữa thị trường phát triển và thị trường Việt Nam
Khía cạnh
Thị trường phát triển (Hoa Kỳ)
Thị trường Việt Nam
Tần suất công bố
Hằng quý (bắt buộc)
Nửa năm đến hằng quý
Độ trễ báo cáo
~60 ngày
Thay đổi, có thể dài hơn
Hiệu quả thị trường
Cao
Trung bình/mới nổi
Phân tích viên theo dõi
Dày đặc
Thưa thớt
Biên độ giá
Không có
Cộng hoặc trừ 7% (HOSE), cộng hoặc trừ 10% (HNX)
Sở hữu nước ngoài
Nhìn chung không hạn chế
Có giới hạn (thường 49%)
Cho vay chứng khoán
Thị trường trưởng thành
Hạn chế/non trẻ
Quy mô RG kỳ vọng
Nhỏ hơn
Có thể lớn hơn
Tính bền vững RG kỳ vọng
Trung bình
Có thể cao hơn
47 Kết luận
Chương này đã trình bày cách triển khai thước đo Return Gap cho ngành quỹ tương hỗ Việt Nam. Return Gap, được định nghĩa là chênh lệch giữa lợi nhuận gộp thực tế của quỹ và lợi nhuận giả định hàm ý từ các khoản nắm giữ được công bố gần nhất, cung cấp một góc nhìn đặc biệt giàu thông tin về giá trị (hoặc chi phí) của các hành động không quan sát được của nhà quản lý quỹ.
Quy trình phân tích của chúng ta minh họa cách:
Chuẩn bị và căn chỉnh các phiên bản dữ liệu nắm giữ của quỹ với dữ liệu cấp cổ phiếu, xử lý đúng các đặc điểm của thị trường Việt Nam như sự kiện doanh nghiệp và thời điểm công bố.
Tính lợi nhuận nắm giữ giả định như lợi nhuận danh mục mua và nắm giữ theo trọng số giá trị, dùng giá trị bằng tiền có độ trễ làm trọng số.
Xây dựng Return Gap bằng cách lấy lợi nhuận gộp của quỹ trừ lợi nhuận nắm giữ giả định, và hình thành tín hiệu dự báo bằng trung bình 12 tháng gần nhất với các độ trễ phù hợp.
Phân loại các quỹ thành các danh mục decile và đánh giá hiệu suất điều chỉnh theo rủi ro bằng các mô hình CAPM, Fama-French và Carhart với sai số chuẩn Newey-West.
Xem xét tính bền vững, các yếu tố quyết định và các mở rộng gồm phân rã, phân tích có điều kiện, dòng vốn vào quỹ, chọn cổ phiếu và các danh mục phân loại kép.
Bằng chứng từ các thị trường phát triển, nơi các quỹ có Return Gap cao vượt các quỹ có Return Gap thấp khoảng 1-2% mỗi năm trên cơ sở điều chỉnh theo rủi ro, cung cấp một chuẩn so sánh tự nhiên. Với hiệu quả thị trường thấp hơn, ít phân tích viên theo dõi hơn và vi cấu trúc đặc thù của thị trường Việt Nam, chúng ta có thể kỳ vọng mức chênh lệch Return Gap còn lớn hơn, phản ánh cả phạm vi lớn hơn cho giao dịch giữa kỳ có kỹ năng lẫn chi phí đại diện lớn hơn.
Đối với giới thực hành, Return Gap là một công cụ có thể ứng dụng trực tiếp để lựa chọn quỹ. Đối với cơ quan quản lý là UBCKNN (SSC) của Việt Nam, Return Gap âm kéo dài có thể báo hiệu các vấn đề đại diện mang tính hệ thống đáng được tăng cường công bố thông tin. Đối với các nhà nghiên cứu học thuật, bối cảnh Việt Nam là một phòng thí nghiệm tự nhiên để kiểm tra liệu các cơ chế đằng sau Return Gap có vận hành khác đi ở thị trường mới nổi hay không.
Các mở rộng trong tương lai có thể gồm dữ liệu nắm giữ hằng ngày, ước tính chi phí giao dịch từ dữ liệu sổ lệnh, tương tác giữa Return Gap và chất lượng quản trị của quỹ, hoặc các phương pháp học máy nhằm cải thiện khả năng dự báo.
Bergstresser, Daniel, John M R Chalmers, và Peter Tufano. 2009. “Assessing the costs and benefits of brokers in the mutual fund industry”. The Review of Financial Studies 22 (10): 4129–56.
Chen, Jun, Shenje Hshieh, Melvyn Teo, và Feng Zhang. 2026. “Immigrants in finance: Evidence from hedge funds”. Management Science. https://doi.org/10.1287/mnsc.2024.07615.
Christoffersen, Susan E K, Richard Evans, và David K Musto. 2013. “What do consumers’ fund flows maximize? Evidence from their brokers’ incentives”. The Journal of Finance 68 (1): 201–35.
Elton, Edwin J, Martin J Gruber, và Christopher R Blake. 2011. “Holdings data, security returns, and the selection of superior mutual funds”. Journal of Financial and Quantitative Analysis 46 (2): 341–67.
Kacperczyk, Marcin, Clemens Sialm, và Lu Zheng. 2008. “Unobserved actions of mutual funds”. The Review of Financial Studies 21 (6): 2379–2416.
Newey, Whitney K, và Kenneth D West. 1987. “A Simple, Positive Semi-Definite, Heteroskedasticity and Autocorrelation”. Econometrica 55 (3): 703–8.
Pool, Veronika K, Clemens Sialm, và Irina Stefanescu. 2016. “It pays to set the menu: Mutual fund investment options in 401(k) plans”. The Journal of Finance 71 (4): 1779–1812.
Sialm, Clemens, Laura T Starks, và Hanjiang Zhang. 2015. “Defined contribution pension plans: Sticky or discerning money?”The Journal of Finance 70 (2): 805–38.
# Chênh lệch lợi nhuận (Return Gap): Đo lường các hành động không quan sát được của nhà quản lý quỹCác nhà quản lý quỹ tương hỗ có quyền tự quyết đáng kể trong các quyết định đầu tư giữa các ngày công bố danh mục bắt buộc. Mặc dù khung pháp lý yêu cầu công bố định kỳ các khoản nắm giữ, những hành động được thực hiện giữa các ngày công bố này (ví dụ: giao dịch, định thời điểm thị trường, cho vay chứng khoán và quản lý tiền mặt mang tính chiến lược) phần lớn vẫn không thể quan sát được đối với nhà đầu tư. Những *hành động không quan sát được* này có thể tác động đáng kể đến hiệu suất quỹ, theo hướng tích cực thông qua hoạt động giao dịch giữa kỳ khéo léo, hoặc theo hướng tiêu cực thông qua chi phí đại diện và hành vi ẩn giấu.@kacperczyk2008unobserved đã phát triển thước đo **Return Gap** để nắm bắt tác động tổng hợp của các hành động không quan sát được này lên lợi nhuận của quỹ. Return Gap được định nghĩa là chênh lệch giữa lợi nhuận thực tế mà quỹ báo cáo và lợi nhuận giả định của một danh mục được đầu tư một cách máy móc vào các khoản nắm giữ được công bố gần nhất của quỹ. Viết dưới dạng công thức:$$\text{Return Gap}_{i,t} = R_{i,t}^{\text{Actual}} - R_{i,t}^{\text{Holdings}}$$ {#eq-return-gap-basic}trong đó $R_{i,t}^{\text{Actual}}$ là lợi nhuận ròng sau chi phí do quỹ $i$ báo cáo trong tháng $t$, được điều chỉnh theo chi phí để thu được lợi nhuận gộp, và $R_{i,t}^{\text{Holdings}}$ là lợi nhuận mua và nắm giữ giả định được tính từ các khoản nắm giữ danh mục được công bố gần nhất.Return Gap dương cho thấy các hành động không quan sát được của nhà quản lý quỹ (ví dụ: giao dịch giữa kỳ, quản lý tiền mặt hoặc các hoạt động khác) đã tạo thêm giá trị so với việc sao chép thụ động các khoản nắm giữ đã công bố. Ngược lại, Return Gap âm kéo dài gợi ý hoạt động giữa kỳ làm hủy hoại giá trị, có thể do chi phí đại diện, thực thi giao dịch kém hoặc phí ẩn.## Vì sao Return Gap quan trọngReturn Gap có ý nghĩa kinh tế vì nhiều lý do:1. **Tính bền vững của hiệu suất**: Các quỹ thuộc decile Return Gap cao nhất có xu hướng vượt các quỹ thuộc decile thấp nhất 1-2% mỗi năm trên cơ sở điều chỉnh theo rủi ro, và mức chênh lệch này kéo dài theo thời gian [@kacperczyk2008unobserved].2. **Phát hiện vấn đề đại diện**: Return Gap âm kéo dài có thể báo hiệu các chi phí ẩn như giao dịch quá mức, chi phí tác động thị trường, thỏa thuận soft-dollar hoặc khai thác giá lỗi thời.3. **Bổ sung cho các thước đo truyền thống**: Không giống các chỉ số dựa trên alpha vốn trộn lẫn kỹ năng chọn cổ phiếu với kỹ năng giao dịch giữa kỳ, Return Gap tách riêng thành phần hiệu suất quy cho các hành động được thực hiện *giữa* các ngày công bố.4. **Hàm ý đối với cơ quan quản lý**: Ở các thị trường mới nổi như Việt Nam, nơi tần suất công bố thông tin và sự giám sát của cơ quan quản lý có thể khác với thị trường phát triển, Return Gap có thể đóng vai trò hệ thống cảnh báo sớm cho việc bảo vệ nhà đầu tư.## Các khoản chi trả ẩn: Chia sẻ doanh thu, phân phối và thiết kế danh mục lựa chọn {#sec-return-gap-revenue-sharing}Return Gap định lượng hệ quả của những gì nhà quản lý *làm* giữa các ngày công bố. Một nhánh nghiên cứu bổ sung cho thấy kết quả của nhà đầu tư cũng được định hình ngang bằng bởi các khoản chi trả luân chuyển giữa quỹ và các đơn vị phân phối, phần lớn nằm ngoài tầm nhìn của nhà đầu tư. @pool2026mutual đưa ra bằng chứng rõ ràng nhất từ các kế hoạch 401(k) của Hoa Kỳ, nơi đơn vị quản lý hồ sơ (recordkeeper) quản lý kế hoạch thường được trả công gián tiếp thông qua chia sẻ doanh thu: các khoản hoàn trả do các quỹ tương hỗ bên thứ ba trong danh mục lựa chọn của kế hoạch chi trả từ tỷ lệ chi phí của họ. Những thỏa thuận này làm méo mó chính danh mục lựa chọn: các quỹ chia sẻ doanh thu có nhiều khả năng được thêm vào và ít khả năng bị loại bỏ hơn, và các kế hoạch chia sẻ doanh thu đắt đỏ hơn nói chung, với tỷ lệ chi phí cao hơn không được bù đắp bởi phí trực tiếp thấp hơn hay hiệu suất tốt hơn. Các khoản hoàn trả cũng tăng theo sức mạnh thị trường của đơn vị quản lý hồ sơ, phù hợp với việc các quỹ chia sẻ doanh thu để mua quyền tiếp cận tài sản hưu trí.Kết quả này mở rộng một nhánh nghiên cứu lâu đời hơn về xung đột phân phối trong quản lý tài sản ủy thác. @pool2016it cho thấy các công ty quản lý quỹ tương hỗ đóng vai trò người được ủy thác của các kế hoạch 401(k) ưu ái các quỹ trực thuộc chính họ trong các quyết định về danh mục lựa chọn, đặc biệt là các quỹ hoạt động kém, và người tham gia không đảo ngược sự ưu ái này. @sialm2015defined thấy rằng dòng vốn của các kế hoạch hưu trí đóng góp xác định phản ứng mạnh với hiệu suất, nhưng phần lớn là do các nhà tài trợ kế hoạch thêm và bớt các lựa chọn trong danh mục, điều này tập trung ảnh hưởng vào chính các trung gian mà chia sẻ doanh thu nhắm tới. Ngoài các kế hoạch hưu trí, @bergstresser2009assessing ghi nhận rằng các quỹ bán qua môi giới có hiệu suất kém hơn các quỹ bán trực tiếp ngay cả trước phí phân phối, và @christoffersen2013what cho thấy các khoản chi trả cho nhà môi giới dự báo dòng vốn vào quỹ và hiệu suất thấp hơn sau đó, cho thấy rằng thù lao của trung gian, chứ không chỉ cầu của nhà đầu tư, dẫn dắt dòng tiền.Những phát hiện này quan trọng đối với Việt Nam vì ngành quỹ của nước ta do kênh phân phối dẫn dắt: phần lớn tài sản của các quỹ mở được huy động qua ngân hàng, công ty chứng khoán và các nền tảng phân phối quỹ được cấp phép, các chương trình hưu trí bổ sung tự nguyện còn non trẻ, và các thỏa thuận phí giữa nhà quản lý quỹ và đơn vị phân phối không được công bố một cách có hệ thống. Khi các sản phẩm theo kiểu danh mục lựa chọn lan rộng qua các nền tảng quỹ, bảo hiểm gắn với hưu trí và các chương trình tiết kiệm do người sử dụng lao động tài trợ, bằng chứng của Hoa Kỳ gợi ý một chương trình nghiên cứu và quản lý rõ ràng: đo lường không chỉ những gì quỹ báo cáo và nắm giữ, mà còn cả việc ai được trả tiền để có vị trí trên "kệ hàng", vì những khoản chi trả này dự báo cả thành phần danh mục lựa chọn lẫn chi phí của nhà đầu tư. Phương pháp Return Gap được phát triển trong chương này và các chẩn đoán dựa trên phí bổ trợ cho nhau trong chương trình đó: một bên theo dõi các hành động ẩn, bên kia theo dõi các khoản chi trả ẩn.## Các đầu vào ẩn: Vốn nhân lực và kỹ năng của quỹ {#sec-return-gap-human-capital}Điều thứ ba mà nhà đầu tư hiếm khi quan sát được là *ai* tạo ra hiệu suất của quỹ. Alpha, Return Gap và các thước đo kỹ năng liên quan là các đầu ra; còn đầu vào là các nhà phân tích và nhân sự định lượng mà công ty quản lý tuyển dụng được. Việc xác định đóng góp nhân quả của những đầu vào này rất khó vì những người tài năng tự lựa chọn vào các quỹ vốn đã hoạt động tốt. @chen2026immigrants giải quyết vấn đề lựa chọn bằng một cuộc xổ số. Các công ty quản lý quỹ phòng hộ của Hoa Kỳ nộp đơn xin thị thực lao động tay nghề cao H-1B, và khi số đơn vượt quá hạn ngạch hằng năm, thị thực được phân bổ bằng bốc thăm ngẫu nhiên, nên hai công ty nộp đơn cùng số lượng thị thực nhưng trúng số lượng khác nhau có thể so sánh với nhau ngay từ đầu. Các công ty trúng nhiều thị thực hơn sau đó mang lại alpha, tỷ số Sharpe và tỷ số thông tin cao hơn. Hiệu ứng này được truy về những người lao động được trả lương cao, có trình độ học vấn cao và kỹ năng định lượng, giúp các quỹ phát triển chiến lược riêng biệt, kinh doanh chênh lệch giá các hiện tượng bất thường nổi bật của cổ phiếu và nới lỏng các ràng buộc về quy mô (capacity). Hai kết quả khác làm rõ thêm cách diễn giải: việc cắt giảm bất ngờ hạn ngạch H-1B làm tổn hại hiệu suất của những quỹ phụ thuộc nhiều nhất vào các lao động như vậy, và việc tạo alpha lớn nhất ở những lao động đến từ các quốc gia có thời gian chờ thường trú nhân Hoa Kỳ lâu nhất, phù hợp với việc các quỹ khai thác một ma sát trên thị trường lao động ràng buộc người lao động với đơn vị bảo lãnh.Thiết kế này có một phiên bản tương tự trực tiếp ở Việt Nam. Các công ty quản lý quỹ ở Việt Nam cạnh tranh nhau để thu hút một nhóm nhỏ các nhà phân tích đạt chứng chỉ CFA và nhân sự được đào tạo về định lượng, các nhà quản lý có liên kết nước ngoài luân chuyển nhân sự nước ngoài ra vào Thành phố Hồ Chí Minh, và các quy định về giấy phép lao động và cấp phép cho chuyên gia nước ngoài thay đổi theo thời gian. Một nhà nghiên cứu có thể quan sát nhân sự ở cấp công ty quản lý, dù từ hồ sơ cấp phép hành nghề quản lý quỹ của UBCKNN (SSC), dữ liệu giấy phép lao động, hay hồ sơ nghề nghiệp kiểu LinkedIn, có thể hỏi liệu các nhân sự có kỹ năng được tuyển có dự báo alpha và Return Gap sau đó hay không, và có thể khai thác các thay đổi quy định về lao động nước ngoài làm cú sốc. Bài học từ @chen2026immigrants là các hành động ẩn và các khoản chi trả ẩn chỉ là một phần của câu chuyện; các đầu vào ẩn cũng quan trọng đối với hiệu suất, và việc phân bổ ngẫu nhiên hoặc gần như ngẫu nhiên các đầu vào này là điều biến mối tương quan giữa tài năng và lợi nhuận thành bằng chứng về kỹ năng.## Ứng dụng vào thị trường Việt NamNgành quỹ tương hỗ Việt Nam, tuy còn non trẻ so với Hoa Kỳ, đã tăng trưởng nhanh chóng kể từ khi các quỹ cổ phiếu trong nước đầu tiên được thành lập vào đầu những năm 2000. Tính đến năm 2024, ngành quỹ mở của Việt Nam quản lý tài sản vượt 100 nghìn tỷ VND, với hàng chục quỹ thiên về cổ phiếu do các công ty quản lý tài sản trong nước và có liên kết nước ngoài điều hành.Một số đặc điểm của thị trường Việt Nam khiến phân tích Return Gap đặc biệt thú vị:- **Tần suất công bố thông tin**: Các quỹ Việt Nam được yêu cầu công bố định kỳ các khoản nắm giữ hàng đầu, nhưng tần suất và mức độ đầy đủ của việc công bố có thể khác với yêu cầu hằng quý của SEC tại Hoa Kỳ.- **Vi cấu trúc thị trường**: HOSE (Sở Giao dịch Chứng khoán TP. Hồ Chí Minh) và HNX (Sở Giao dịch Chứng khoán Hà Nội) áp dụng biên độ giá hằng ngày (cộng hoặc trừ 7% trên HOSE, cộng hoặc trừ 10% trên HNX), thanh toán T+2 và giới hạn sở hữu nước ngoài, những yếu tố có thể hạn chế hoặc tạo điều kiện cho một số chiến lược giao dịch giữa kỳ.- **Bất đối xứng thông tin**: Ở thị trường mới nổi có ít phân tích viên theo dõi hơn, phạm vi cho giao dịch giữa kỳ có thông tin và do đó Return Gap dương có thể lớn hơn so với các thị trường hiệu quả hơn.- **Môi trường pháp lý**: Ủy ban Chứng khoán Nhà nước (SSC) của Việt Nam đã dần tăng cường các yêu cầu về công bố thông tin và quản trị, khiến phân tích Return Gap theo thời gian đặc biệt có giá trị.# Khung lý thuyết {#sec-return-gaptheory}## Phân rã lợi nhuận của quỹXét một quỹ tương hỗ $i$ công bố các khoản nắm giữ danh mục tại các thời điểm rời rạc $\tau_1, \tau_2, \ldots$ Như được công bố tại thời điểm $\tau_k$, quỹ nắm giữ $N_k$ chứng khoán với các tỷ trọng $\{w_{j,\tau_k}\}_{j=1}^{N_k}$, trong đó $w_{j,\tau_k}$ biểu thị tỷ trọng danh mục của chứng khoán $j$.Giữa các ngày công bố $\tau_k$ và $\tau_{k+1}$, *lợi nhuận gộp thực tế* của quỹ trong tháng $t$ có thể được phân rã như sau:$$R_{i,t}^{\text{Gross}} = R_{i,t}^{\text{Holdings}} + \underbrace{R_{i,t}^{\text{Gross}} - R_{i,t}^{\text{Holdings}}}_{\text{Return Gap}}$$ {#eq-decomposition}Lợi nhuận nắm giữ giả định $R_{i,t}^{\text{Holdings}}$ được tính là lợi nhuận theo trọng số giá trị của danh mục mua và nắm giữ dựa trên lần công bố gần nhất:$$R_{i,t}^{\text{Holdings}} = \sum_{j=1}^{N_k} \tilde{w}_{j,t-1} \cdot r_{j,t}$$ {#eq-holdings-return}trong đó $r_{j,t}$ là lợi nhuận của chứng khoán $j$ trong tháng $t$, và $\tilde{w}_{j,t-1}$ là tỷ trọng danh mục *đã biến đổi* vào cuối tháng $t-1$, phản ánh sự trôi tỷ trọng do mua và nắm giữ từ các tỷ trọng công bố ban đầu:$$\tilde{w}_{j,t-1} = \frac{w_{j,\tau_k} \prod_{s=\tau_k+1}^{t-1}(1 + r_{j,s})}{\sum_{\ell=1}^{N_k} w_{\ell,\tau_k} \prod_{s=\tau_k+1}^{t-1}(1 + r_{\ell,s})}$$ {#eq-evolved-weights}Trong thực tế, thay vì theo dõi tường minh các tỷ trọng đã biến đổi, chúng ta dùng giá trị bằng đô la (ở đây là VND) của các vị thế nắm giữ (số cổ phiếu nắm giữ nhân với giá) làm cách gán trọng số tự nhiên.## Thước đo Return Gap### Return Gap gộpReturn Gap như được @kacperczyk2008unobserved định nghĩa ban đầu sử dụng lợi nhuận *gộp* (trước chi phí):$$\text{RG}_{i,t} = R_{i,t}^{\text{Gross}} - R_{i,t}^{\text{Holdings}} = \left(R_{i,t}^{\text{Net}} + \frac{\text{Expense Ratio}_{i,t}}{12}\right) - R_{i,t}^{\text{Holdings}}$$ {#eq-return-gap-gross}trong đó $R_{i,t}^{\text{Net}}$ là lợi nhuận ròng sau chi phí được báo cáo và tỷ lệ chi phí hằng năm được chia cho 12 để xấp xỉ khoản chi phí hằng tháng.### Các nguồn của Return GapReturn Gap nắm bắt một số thành phần [@kacperczyk2008unobserved; @elton2011holdings]:$$\text{RG}_{i,t} = \underbrace{\Delta_{\text{trade}}}_{\text{Interim trading}} + \underbrace{\Delta_{\text{cash}}}_{\text{Cash drag/return}} + \underbrace{\Delta_{\text{fees}}}_{\text{Hidden fees}} + \underbrace{\Delta_{\text{lend}}}_{\text{Securities lending}} + \underbrace{\varepsilon_t}_{\text{Noise}}$$ {#eq-decompose-rg}trong đó:- $\Delta_{\text{trade}}$: Tác động lên lợi nhuận của việc mua và bán chứng khoán giữa các ngày công bố. Các nhà quản lý có kỹ năng tạo ra $\Delta_{\text{trade}}$ dương nhờ định thời điểm giao dịch.- $\Delta_{\text{cash}}$: Hiệu ứng của việc nắm giữ tiền mặt hoặc các khoản tương đương tiền không được phản ánh trong các công bố nắm giữ cổ phiếu. Trong thị trường tăng, tiền mặt tạo ra lực cản (đóng góp âm); trong thị trường giảm, tiền mặt tạo ra lớp đệm.- $\Delta_{\text{fees}}$: Chi phí giao dịch, hoa hồng môi giới và mọi khoản phí ẩn không phản ánh trong tỷ lệ chi phí công bố.- $\Delta_{\text{lend}}$: Doanh thu từ các chương trình cho vay chứng khoán, tạo ra Return Gap dương.- $\varepsilon_t$: Nhiễu đo lường do chênh lệch thời điểm, giá lỗi thời hoặc lỗi dữ liệu.### Return Gap dự báoĐể hình thành các danh mục có thể giao dịch và tránh thiên lệch nhìn trước, @kacperczyk2008unobserved dùng Return Gap *trung bình 12 tháng gần nhất*, trễ một quý để tính đến độ trễ báo cáo:$$\overline{\text{RG}}_{i,t}^{12} = \frac{1}{12} \sum_{s=1}^{12} \text{RG}_{i,t-s}$$ {#eq-trailing-rg}Độ trễ bổ sung 3 tháng (một quý) bảo đảm tín hiệu Return Gap chỉ dựa trên thông tin mà nhà đầu tư có được tại thời điểm hình thành danh mục. Điều này đặc biệt quan trọng ở Việt Nam, nơi việc báo cáo của quỹ có thể bị chậm.## Đánh giá hiệu suất điều chỉnh theo rủi roĐể đánh giá liệu các danh mục được sắp xếp theo Return Gap có tạo ra lợi nhuận điều chỉnh theo rủi ro thực sự hay không, chúng ta sử dụng một số mô hình nhân tố.### Alpha CAPM$$R_{p,t} - R_{f,t} = \alpha_p + \beta_p (R_{m,t} - R_{f,t}) + \epsilon_{p,t}$$ {#eq-capm}### Mô hình ba nhân tố Fama-French$$R_{p,t} - R_{f,t} = \alpha_p + \beta_{1,p} \cdot \text{MKT}_t + \beta_{2,p} \cdot \text{SMB}_t + \beta_{3,p} \cdot \text{HML}_t + \epsilon_{p,t}$$ {#eq-ff3}### Mô hình bốn nhân tố Carhart$$R_{p,t} - R_{f,t} = \alpha_p + \beta_{1,p} \cdot \text{MKT}_t + \beta_{2,p} \cdot \text{SMB}_t + \beta_{3,p} \cdot \text{HML}_t + \beta_{4,p} \cdot \text{UMD}_t + \epsilon_{p,t}$$ {#eq-carhart}trong đó $\text{UMD}_t$ là nhân tố động lượng (up minus down).### Mô hình năm nhân tố Fama-FrenchĐể điều chỉnh rủi ro toàn diện hơn, phù hợp với thị trường Việt Nam:$$R_{p,t} - R_{f,t} = \alpha_p + \beta_1 \text{MKT}_t + \beta_2 \text{SMB}_t + \beta_3 \text{HML}_t + \beta_4 \text{RMW}_t + \beta_5 \text{CMA}_t + \epsilon_{p,t}$$ {#eq-ff5}trong đó $\text{RMW}_t$ (robust minus weak) nắm bắt khả năng sinh lời và $\text{CMA}_t$ (conservative minus aggressive) nắm bắt các mô thức đầu tư.## Sai số chuẩn Newey-WestVì lợi nhuận danh mục có thể có tương quan chuỗi, chúng ta sử dụng sai số chuẩn @newey1987simple với $L$ độ trễ:$$\hat{V}(\hat{\alpha}) = T \left(\sum_{t=1}^{T} \mathbf{x}_t \mathbf{x}_t'\right)^{-1} \hat{S} \left(\sum_{t=1}^{T} \mathbf{x}_t \mathbf{x}_t'\right)^{-1}$$ {#eq-newey-west-var}trong đó bộ ước lượng hiệp phương sai HAC là:$$\hat{S} = \hat{\Gamma}_0 + \sum_{\ell=1}^{L} \left(1 - \frac{\ell}{L+1}\right)\left(\hat{\Gamma}_\ell + \hat{\Gamma}_\ell'\right)$$ {#eq-hac}và $\hat{\Gamma}_\ell = \frac{1}{T}\sum_{t=\ell+1}^{T} \hat{\epsilon}_t \hat{\epsilon}_{t-\ell} \mathbf{x}_t \mathbf{x}_{t-\ell}'$. Cách chọn độ trễ tiêu chuẩn là $L = \lfloor 4(T/100)^{2/9} \rfloor$.# Dữ liệu và xây dựng mẫu {#sec-return-gapdata}## Nguồn dữ liệu@tbl-return-gaps-data-sources trình bày các nguồn được dùng để xây dựng return gap.| Nhóm dữ liệu | Nguồn | Mô tả ||:-----------------------|:-----------------------|:-----------------------|| Các khoản nắm giữ của quỹ | DataCore Fund Holdings | Các vị thế danh mục được công bố gồm mã chứng khoán, số cổ phiếu nắm giữ, ngày báo cáo và ngày phiên bản (nộp hồ sơ) || Lợi nhuận của quỹ | DataCore Fund Performance | Lợi nhuận ròng dựa trên NAV hằng tháng, tổng tài sản ròng và tỷ lệ chi phí || Đặc điểm của quỹ | DataCore Fund Master | Mã mục tiêu của quỹ, ngày thành lập, công ty quản lý, phong cách đầu tư || Giá và lợi nhuận cổ phiếu | DataCore Equity Market | Giá điều chỉnh, lợi nhuận, số cổ phiếu lưu hành và các sự kiện doanh nghiệp hằng ngày và hằng tháng của các chứng khoán niêm yết trên HOSE và HNX || Các nhân tố rủi ro | DataCore / Tự xây dựng | Các danh mục nhân tố thị trường Việt Nam (MKT, SMB, HML, UMD, RMW, CMA) |: Nguồn dữ liệu cho phân tích Return Gap tại Việt Nam {#tbl-return-gaps-data-sources}## Thiết lập môi trường```{python}#| label: setup-environment#| code-summary: "Import libraries and configure settings"import pandas as pdimport numpy as npimport matplotlib.pyplot as pltimport seaborn as snsimport statsmodels.api as smfrom statsmodels.regression.linear_model import OLSfrom scipy import statsfrom datetime import datetime, timedeltafrom dateutil.relativedelta import relativedeltaimport warningswarnings.filterwarnings("ignore")plt.rcParams.update({"figure.figsize": (10, 6),"font.size": 12,"axes.titlesize": 14,"axes.labelsize": 12,"xtick.labelsize": 10,"ytick.labelsize": 10,"legend.fontsize": 10,"figure.dpi": 150,"savefig.dpi": 300,"font.family": "serif",})sns.set_style("whitegrid")np.random.seed(42)```## Tải và chuẩn bị dữ liệu thị trường chứng khoán {#sec-return-gapstock-data}Bước đầu tiên là tải dữ liệu cấp cổ phiếu, vốn là nền tảng để tính lợi nhuận nắm giữ giả định.```{python}#| label: load-stock-data#| code-summary: "Load stock prices and returns from DataCore"# ============================================================# In production, replace with actual DataCore API calls:# from datacore import DataCoreClient# client = DataCoreClient(api_key="YOUR_KEY")# stock_data = client.get_equity_monthly(# exchange=["HOSE", "HNX"],# start_date="2010-01-01",# end_date="2024-12-31",# fields=["ticker", "date", "close_adj", "return_monthly",# "shares_outstanding", "market_cap"]# )# ============================================================def generate_stock_data( n_stocks: int=300, start_date: str="2012-01-01", end_date: str="2024-12-31",) -> pd.DataFrame:""" Generate simulated monthly stock data mimicking Vietnamese equity market characteristics. """ dates = pd.date_range(start_date, end_date, freq="ME") tickers = [f"VN{str(i).zfill(4)}"for i inrange(1, n_stocks +1)] records = []for ticker in tickers: list_offset = np.random.randint(0, max(1, len(dates) //3)) available_dates = dates[list_offset:] mu = np.random.normal(0.008, 0.005) sigma = np.random.uniform(0.06, 0.15) beta = np.random.uniform(0.5, 1.8) market_shocks = np.random.normal(0.005, 0.06, len(available_dates)) idio_shocks = np.random.normal(0, sigma, len(available_dates)) returns = mu + beta * market_shocks + idio_shocks returns = np.clip(returns, -0.30, 0.40) price = np.random.uniform(10, 150) prices = [price]for r in returns[:-1]: price = price * (1+ r) prices.append(price) shares = np.random.uniform(50, 500) *1e6 shares_series = np.full(len(available_dates), shares)for i, d inenumerate(available_dates): records.append({"ticker": ticker, "date": d,"close_adj": prices[i], "ret": returns[i],"shares_outstanding": shares_series[i],"market_cap": prices[i] * shares_series[i] /1e9, }) df = pd.DataFrame(records) df["date"] = pd.to_datetime(df["date"]) df = df.sort_values(["ticker", "date"]) df["close_adj_lag"] = df.groupby("ticker")["close_adj"].shift(1)return dfstock_data = generate_stock_data()print(f"Stock data: {stock_data.shape[0]:,} stock-months")print(f"Unique stocks: {stock_data['ticker'].nunique()}")print(f"Date range: {stock_data['date'].min():%Y-%m} to "f"{stock_data['date'].max():%Y-%m}")stock_data.head(10)```## Tải dữ liệu nắm giữ của quỹ {#sec-return-gapholdings-data}```{python}#| label: load-holdings-data#| code-summary: "Load fund holdings from DataCore"def generate_holdings_data( stock_data: pd.DataFrame, n_funds: int=50, start_date: str="2012-06-30", end_date: str="2024-12-31",) -> pd.DataFrame:""" Generate simulated fund holdings data. Each fund holds 15-80 stocks, disclosed semi-annually or quarterly. """ dates = pd.date_range(start_date, end_date, freq="ME") tickers = stock_data["ticker"].unique() fund_ids = [f"FUND{str(i).zfill(3)}"for i inrange(1, n_funds +1)] records = []for fund_id in fund_ids: inception_idx = np.random.randint(0, max(1, len(dates) //4)) freq =3if np.random.random() <0.7else6 n_stocks_held = np.random.randint(15, 80) core_stocks = np.random.choice(tickers, size=n_stocks_held, replace=False) report_dates = dates[inception_idx::freq]for rdate in report_dates: filing_delay = np.random.randint(1, 4) fdate = rdate + pd.DateOffset(months=filing_delay) turnover = np.random.uniform(0.05, 0.20) n_replace =max(1, int(n_stocks_held * turnover)) replace_idx = np.random.choice(len(core_stocks), size=n_replace, replace=False) new_stocks = np.random.choice(tickers, size=n_replace, replace=False) core_stocks[replace_idx] = new_stocksfor ticker in core_stocks: shares = np.random.uniform(100_000, 5_000_000) records.append({"fund_id": fund_id, "report_date": rdate,"filing_date": fdate, "ticker": ticker,"shares_held": shares, }) df = pd.DataFrame(records) df["report_date"] = pd.to_datetime(df["report_date"]) df["filing_date"] = pd.to_datetime(df["filing_date"])return dfholdings_raw = generate_holdings_data(stock_data)print(f"Holdings records: {holdings_raw.shape[0]:,}")print(f"Unique funds: {holdings_raw['fund_id'].nunique()}")holdings_raw.head(10)```## Tải lợi nhuận và đặc điểm của quỹ {#sec-return-gapfund-returns}```{python}#| label: load-fund-returns#| code-summary: "Load fund NAV returns and expense data"def generate_fund_returns(holdings, start_date="2012-01-01", end_date="2024-12-31"):"""Generate monthly fund-level net returns, TNA, and expense ratios.""" fund_ids = holdings["fund_id"].unique() dates = pd.date_range(start_date, end_date, freq="ME") records = []for fund_id in fund_ids: fund_start = holdings.loc[holdings["fund_id"] == fund_id, "report_date"].min() - pd.DateOffset(months=3) fund_dates = dates[dates >= fund_start] exp_ratio = np.random.uniform(0.010, 0.025) base_tna = np.random.uniform(50, 2000) mu = np.random.normal(0.007, 0.003) sigma = np.random.uniform(0.04, 0.09) tna = base_tnafor d in fund_dates: ret = np.clip(np.random.normal(mu, sigma), -0.25, 0.35) tna =max(tna * (1+ ret) + np.random.normal(0, base_tna *0.02), 10) records.append({"fund_id": fund_id, "date": d, "net_return": ret,"tna": tna, "expense_ratio": exp_ratio + np.random.normal(0, 0.001)}) df = pd.DataFrame(records) df["date"] = pd.to_datetime(df["date"]) df["expense_ratio"] = df["expense_ratio"].clip(0.005, 0.035)return dffund_returns = generate_fund_returns(holdings_raw)print(f"Fund-month observations: {fund_returns.shape[0]:,}")fund_returns.head(10)```## Chọn mẫu: Các quỹ cổ phiếu trong nước {#sec-return-gapsample-selection}Theo cách tiếp cận của @kacperczyk2008unobserved, chúng ta giới hạn mẫu ở các quỹ cổ phiếu trong nước.```{python}#| label: sample-selection#| code-summary: "Filter to domestic equity funds"equity_objectives = ["EQUITY_DOMESTIC", "EQUITY_GROWTH", "EQUITY_VALUE","EQUITY_BLEND", "EQUITY_LARGE_CAP", "EQUITY_MID_CAP","EQUITY_SMALL_CAP",]fund_ids = fund_returns["fund_id"].unique()fund_master = pd.DataFrame({"fund_id": fund_ids,"objective": np.random.choice( equity_objectives + ["BOND", "BALANCED", "MONEY_MARKET"], size=len(fund_ids), p=[0.08, 0.08, 0.06, 0.10, 0.08, 0.06, 0.06, 0.15, 0.18, 0.15], ),})equity_fund_ids = fund_master.loc[ fund_master["objective"].isin(equity_objectives), "fund_id"].valuesprint(f"Total funds: {len(fund_ids)}")print(f"Equity funds: {len(equity_fund_ids)} ({len(equity_fund_ids)/len(fund_ids)*100:.1f}%)")print("\nObjective distribution:")print(fund_master["objective"].value_counts().to_string())```# Tính Return Gap {#sec-return-gapcomputing}## Bước 1: Chuẩn bị các phiên bản dữ liệu nắm giữ {#sec-return-gapvintages}Một bước đầu tiên quan trọng là xử lý đúng cấu trúc *phiên bản* (vintage) của dữ liệu nắm giữ. Mỗi báo cáo nắm giữ có hai ngày then chốt: **ngày báo cáo** ($\tau$, ngày tham chiếu) và **ngày nộp hồ sơ** ($f$, khi thông tin được công bố công khai). Chúng ta chỉ giữ phiên bản đầu tiên cho mỗi cặp quỹ–ngày báo cáo.```{python}#| label: prepare-vintages#| code-summary: "Process holdings vintages and determine holding periods"def prepare_holdings_vintages(holdings, max_holding_months=6):"""Process holdings vintages and compute next report dates.""" first_vintage = ( holdings.sort_values(["fund_id", "report_date", "filing_date"]) .groupby(["fund_id", "report_date"]) .agg(filing_date=("filing_date", "first")) .reset_index() ) first_vintage = first_vintage.sort_values(["fund_id", "report_date"]) first_vintage["next_report_date"] = first_vintage.groupby("fund_id")["report_date"].shift(-1) max_date = first_vintage["report_date"] + pd.DateOffset(months=max_holding_months) first_vintage["next_report_date"] = first_vintage["next_report_date"].fillna(max_date) first_vintage["next_report_date"] = first_vintage[["next_report_date"]].min(axis=1).clip(upper=max_date) first_vintage["next_report_date"] = first_vintage["next_report_date"] + pd.offsets.MonthEnd(0) result = holdings.merge(first_vintage, on=["fund_id", "report_date", "filing_date"], how="inner")return resultholdings_vintaged = prepare_holdings_vintages(holdings_raw)print(f"Holdings after vintage processing: {holdings_vintaged.shape[0]:,} records")sample_fund = holdings_vintaged["fund_id"].iloc[0](holdings_vintaged.loc[holdings_vintaged["fund_id"] == sample_fund] [["fund_id", "report_date", "filing_date", "next_report_date"]] .drop_duplicates().head(8))```## Bước 2: Điều chỉnh số cổ phiếu theo các sự kiện doanh nghiệp {#sec-return-gapadjust-shares}```{python}#| label: adjust-shares#| code-summary: "Adjust shares held for corporate actions"def adjust_holdings_shares(holdings, stock_data):"""Adjust shares for splits, bonuses, rights. Simulated: factor=1.""" holdings["shares_adj"] = holdings["shares_held"]return holdingsholdings_adj = adjust_holdings_shares(holdings_vintaged, stock_data)```## Bước 3: Tính lợi nhuận nắm giữ giả định {#sec-return-gaphypothetical-returns}Đây là phép tính cốt lõi. Với mỗi quỹ, chúng ta lấy các khoản nắm giữ được công bố tại ngày báo cáo $\tau$, và với mỗi tháng $t$ trong $(\tau, \tau_{\text{next}}]$, tính lợi nhuận theo trọng số giá trị, dùng giá trị bằng tiền có độ trễ làm trọng số.```{python}#| label: compute-holdings-returns#| code-summary: "Compute value-weighted hypothetical portfolio returns"def compute_holdings_returns(holdings, stock_data, min_stocks=10, min_assets_bn=5.0):"""Compute monthly hypothetical buy-and-hold portfolio returns.""" merged = holdings.merge(stock_data, on="ticker", how="inner") mask = (merged["date"] > merged["report_date"]) & (merged["date"] <= merged["next_report_date"]) merged = merged.loc[mask].copy() merged["hvalue_lag"] = merged["shares_adj"] * merged["close_adj_lag"] merged = merged.loc[merged["hvalue_lag"] >0].copy() merged = merged.drop_duplicates(subset=["fund_id", "date", "report_date", "ticker"], keep="first")def weighted_return(group): weights = group["hvalue_lag"] total_weight = weights.sum()if total_weight <=0:return pd.Series({"hret": np.nan, "n_stocks": 0, "assets_lag_bn": 0}) wret = np.average(group["ret"], weights=weights)return pd.Series({"hret": wret, "n_stocks": len(group), "assets_lag_bn": total_weight /1e9}) portfolio_returns = ( merged.groupby(["fund_id", "date"]) .apply(weighted_return, include_groups=False).reset_index() ) portfolio_returns["assets_bn"] = portfolio_returns["assets_lag_bn"] * (1+ portfolio_returns["hret"]) mask = (portfolio_returns["n_stocks"] >= min_stocks) & (portfolio_returns["assets_bn"] >= min_assets_bn)return portfolio_returns.loc[mask].copy()holdings_returns = compute_holdings_returns(holdings_adj, stock_data)print(f"Fund-month observations (hypothetical returns): {holdings_returns.shape[0]:,}")print(f"Unique funds: {holdings_returns['fund_id'].nunique()}")print(f"\nSummary:")print(holdings_returns[["hret", "n_stocks", "assets_bn"]].describe().round(4).to_string())```## Bước 4: Tính lợi nhuận gộp của quỹ {#sec-return-gapgross-returns}```{python}#| label: compute-gross-returns#| code-summary: "Compute gross fund returns"def prepare_fund_returns(fund_returns, equity_fund_ids):"""Prepare fund-level gross returns.""" df = fund_returns.loc[fund_returns["fund_id"].isin(equity_fund_ids)].copy() df["expense_ratio"] = df["expense_ratio"].fillna(df.groupby("fund_id")["expense_ratio"].transform("median")) df["gross_return"] = df["net_return"] + df["expense_ratio"] /12 df = df.sort_values(["fund_id", "date"]) df["tna_lag"] = df.groupby("fund_id")["tna"].shift(1).fillna(df["tna"])return dffund_ret_clean = prepare_fund_returns(fund_returns, equity_fund_ids)print(f"Equity fund-months: {fund_ret_clean.shape[0]:,}")```## Bước 5: Kết hợp và tính Return Gap {#sec-return-gapmerge-return-gap}```{python}#| label: compute-return-gap#| code-summary: "Merge actual and hypothetical returns to compute Return Gap"def compute_return_gap(holdings_returns, fund_returns):"""Compute Return Gap and trailing averages.""" merged = holdings_returns.merge( fund_returns[["fund_id", "date", "net_return", "gross_return", "expense_ratio", "tna"]], on=["fund_id", "date"], how="inner", ) merged["return_gap"] = merged["gross_return"] - merged["hret"] merged = merged.sort_values(["fund_id", "date"]) merged["rg_12m"] = merged.groupby("fund_id")["return_gap"].transform(lambda x: x.rolling(12, min_periods=8).mean() ) merged["rg_12m_lag4"] = merged.groupby("fund_id")["rg_12m"].shift(4)return mergedreturn_gap_data = compute_return_gap(holdings_returns, fund_ret_clean)print(f"Return Gap observations: {return_gap_data.shape[0]:,}")print(f"\nSummary:")print(return_gap_data[["return_gap", "rg_12m", "rg_12m_lag4"]].describe().round(6).to_string())```## Phân phối của Return Gap```{python}#| label: fig-return-gap-distribution#| fig-cap: "Phân phối của Return Gap hằng tháng trên toàn bộ các quan sát quỹ–tháng."#| fig-width: 12#| fig-height: 5fig, axes = plt.subplots(1, 2, figsize=(12, 5))rg = return_gap_data["return_gap"].dropna()rg_trimmed = rg.clip(rg.quantile(0.01), rg.quantile(0.99))axes[0].hist(rg_trimmed, bins=80, density=True, alpha=0.7, color="#2C5F8A", edgecolor="white", linewidth=0.5)axes[0].axvline(rg.mean(), color="#D32F2F", linestyle="--", linewidth=2, label=f"Mean = {rg.mean():.4f}")axes[0].axvline(rg.median(), color="#FF8F00", linestyle="-.", linewidth=2, label=f"Median = {rg.median():.4f}")axes[0].set_xlabel("Monthly Return Gap")axes[0].set_ylabel("Density")axes[0].set_title("Panel A: Monthly Return Gap")axes[0].legend(frameon=True)rg12 = return_gap_data["rg_12m"].dropna()rg12_trimmed = rg12.clip(rg12.quantile(0.01), rg12.quantile(0.99))axes[1].hist(rg12_trimmed, bins=80, density=True, alpha=0.7, color="#1B5E20", edgecolor="white", linewidth=0.5)axes[1].axvline(rg12.mean(), color="#D32F2F", linestyle="--", linewidth=2, label=f"Mean = {rg12.mean():.4f}")axes[1].axvline(rg12.median(), color="#FF8F00", linestyle="-.", linewidth=2, label=f"Median = {rg12.median():.4f}")axes[1].set_xlabel("Trailing 12-Month Average Return Gap")axes[1].set_ylabel("Density")axes[1].set_title("Panel B: 12-Month Average Return Gap")axes[1].legend(frameon=True)plt.tight_layout()plt.show()```## Chuỗi thời gian của Return Gap chéo```{python}#| label: fig-return-gap-timeseries#| fig-cap: "Chuỗi thời gian các thống kê chéo của Return Gap. Đường liền: trung vị, vùng tô bóng: khoảng tứ phân vị (IQR), đường nét đứt: trung bình."#| fig-width: 12#| fig-height: 5ts_stats = ( return_gap_data.groupby("date")["return_gap"] .agg(["mean", "median", lambda x: x.quantile(0.25), lambda x: x.quantile(0.75)]) .rename(columns={"<lambda_0>": "p25", "<lambda_1>": "p75"}).reset_index())fig, ax = plt.subplots(figsize=(12, 5))ax.fill_between(ts_stats["date"], ts_stats["p25"], ts_stats["p75"], alpha=0.3, color="#2C5F8A", label="IQR")ax.plot(ts_stats["date"], ts_stats["median"], color="#2C5F8A", linewidth=2, label="Median")ax.plot(ts_stats["date"], ts_stats["mean"], color="#D32F2F", linestyle="--", linewidth=1.5, label="Mean")ax.axhline(0, color="black", linewidth=0.8)ax.set_xlabel("Date")ax.set_ylabel("Monthly Return Gap")ax.set_title("Cross-Sectional Distribution of Return Gap Over Time")ax.legend(frameon=True)plt.tight_layout()plt.show()```# Phân tích phân loại danh mục {#sec-return-gapportfolios}## Hình thành các danh mục decile theo Return Gap {#sec-return-gapdecile-portfolios}Mỗi tháng $t$, chúng ta phân loại các quỹ thành các danh mục decile dựa trên Return Gap trung bình 12 tháng có độ trễ của chúng ($\overline{\text{RG}}_{i,t-4}^{12}$). Danh mục 1 gồm các quỹ có Return Gap thấp nhất.```{python}#| label: form-decile-portfolios#| code-summary: "Sort funds into decile portfolios"def form_return_gap_portfolios(data, n_portfolios=10, sort_var="rg_12m_lag4"):"""Form portfolios by sorting funds into quantile groups.""" df = data.dropna(subset=[sort_var]).copy() df["portfolio"] = ( df.groupby("date")[sort_var] .transform(lambda x: pd.qcut(x, n_portfolios, labels=False, duplicates="drop")) ) +1return dfn_portfolios =10portfolio_data = form_return_gap_portfolios(return_gap_data, n_portfolios=n_portfolios)print(f"Observations with portfolio assignment: {portfolio_data.shape[0]:,}")```## Lợi nhuận danh mục```{python}#| label: compute-portfolio-returns#| code-summary: "Compute EW and VW portfolio returns"def compute_portfolio_returns(data, n_portfolios=10):"""Compute equal- and value-weighted monthly returns.""" ew = data.groupby(["date", "portfolio"]).agg( ew_ret=("net_return", "mean"), n_funds=("fund_id", "count")).reset_index()def vw_func(group): w = group["tna"].clip(lower=0)return np.average(group["net_return"], weights=w) if w.sum() >0else group["net_return"].mean() vw = data.groupby(["date", "portfolio"]).apply(vw_func, include_groups=False).reset_index(name="vw_ret")return ew.merge(vw, on=["date", "portfolio"], how="left")port_returns = compute_portfolio_returns(portfolio_data)port_wide = port_returns.pivot_table(index="date", columns="portfolio", values=["ew_ret", "vw_ret"])port_wide[("ew_ret", "LS")] = port_wide[("ew_ret", n_portfolios)] - port_wide[("ew_ret", 1)]port_wide[("vw_ret", "LS")] = port_wide[("vw_ret", n_portfolios)] - port_wide[("vw_ret", 1)]print("EW portfolio returns (annualized, %):")print((port_wide["ew_ret"].mean() *12*100).round(2).to_string())```## Đặc điểm của các danh mục theo Return Gap```{python}#| label: tbl-portfolio-characteristics#| tbl-cap: "Đặc điểm của các danh mục decile được phân loại theo Return Gap."chars = portfolio_data.groupby("portfolio").agg( avg_rg=("return_gap", "mean"), avg_rg12=("rg_12m_lag4", "mean"), avg_net_ret=("net_return", "mean"), avg_gross_ret=("gross_return", "mean"), avg_hret=("hret", "mean"), avg_expense=("expense_ratio", "mean"), avg_tna=("tna", "mean"), avg_nstocks=("n_stocks", "mean"), n_obs=("fund_id", "count"),).round(4)dc = chars.copy()dc.columns = ["Avg RG", "Avg RG(12m)", "Net Ret", "Gross Ret", "Hold Ret", "Expense", "TNA(Bn)", "#Stocks", "#Obs"]for col in ["Avg RG", "Avg RG(12m)", "Net Ret", "Gross Ret", "Hold Ret", "Expense"]: dc[col] = (dc[col] *100).round(3)dc["TNA(Bn)"] = dc["TNA(Bn)"].round(1)dc["#Stocks"] = dc["#Stocks"].round(1)print(dc.to_string())```## Lợi nhuận tích lũy của các danh mục cực đoan```{python}#| label: fig-cumulative-returns#| fig-cap: "Lợi nhuận tích lũy của các danh mục phân loại theo Return Gap: P10 (RG cao nhất) so với P1 (thấp nhất), và mức chênh lệch mua–bán khống."#| fig-width: 12#| fig-height: 6cum_ret = pd.DataFrame(index=port_wide.index)cum_ret["P1 (Low RG)"] = (1+ port_wide[("ew_ret", 1)]).cumprod()cum_ret["P10 (High RG)"] = (1+ port_wide[("ew_ret", n_portfolios)]).cumprod()cum_ret["L/S (P10-P1)"] = (1+ port_wide[("ew_ret", "LS")]).cumprod()fig, ax = plt.subplots(figsize=(12, 6))colors = {"P1 (Low RG)": "#D32F2F", "P10 (High RG)": "#1B5E20", "L/S (P10-P1)": "#1565C0"}styles = {"P1 (Low RG)": "--", "P10 (High RG)": "-", "L/S (P10-P1)": "-."}for col in cum_ret.columns: ax.plot(cum_ret.index, cum_ret[col], label=col, color=colors[col], linestyle=styles[col], linewidth=2)ax.axhline(1, color="black", linewidth=0.8, alpha=0.5)ax.set_xlabel("Date")ax.set_ylabel("Cumulative Return (Growth of 1 VND)")ax.set_title("Cumulative Performance of Return Gap Portfolios")ax.legend(frameon=True, loc="upper left")ax.set_yscale("log")plt.tight_layout()plt.show()```# Hiệu suất điều chỉnh theo rủi ro {#sec-return-gaprisk-adjusted}## Các nhân tố rủi ro```{python}#| label: construct-risk-factors#| code-summary: "Generate Vietnamese market factor returns"def generate_factor_returns(start_date="2012-01-01", end_date="2024-12-31"):"""Generate simulated Vietnamese market factor returns.""" dates = pd.date_range(start_date, end_date, freq="ME") n =len(dates)return pd.DataFrame({"date": dates,"rf": np.random.normal(0.004, 0.001, n).clip(0.001, 0.008),"mkt_rf": np.random.normal(0.008, 0.055, n),"smb": np.random.normal(0.003, 0.035, n),"hml": np.random.normal(0.002, 0.030, n),"umd": np.random.normal(0.005, 0.045, n),"rmw": np.random.normal(0.002, 0.025, n),"cma": np.random.normal(0.001, 0.020, n), })factors = generate_factor_returns()print("Factor summary (monthly %):")print((factors.drop(columns="date").describe() *100).round(3).to_string())```## Ước lượng alpha```{python}#| label: estimate-alphas#| code-summary: "Estimate risk-adjusted alphas with Newey-West SEs"def estimate_portfolio_alphas(port_returns, factors, n_portfolios=10, nw_lags=6):"""Estimate alphas using multiple factor models.""" ew_wide = port_returns.pivot_table(index="date", columns="portfolio", values="ew_ret")if n_portfolios in ew_wide.columns and1in ew_wide.columns: ew_wide["LS"] = ew_wide[n_portfolios] - ew_wide[1] merged = ew_wide.merge(factors, on="date", how="inner") results = [] portfolios =list(range(1, n_portfolios +1)) + ["LS"]for port in portfolios:if port notin merged.columns: continue y_raw = merged[port].dropna() idx = y_raw.index rf = merged.loc[idx, "rf"]; mkt = merged.loc[idx, "mkt_rf"] smb = merged.loc[idx, "smb"]; hml = merged.loc[idx, "hml"] umd = merged.loc[idx, "umd"]; rmw = merged.loc[idx, "rmw"] cma = merged.loc[idx, "cma"] y_ex = y_raw - rf models = {"Raw Mean": (y_raw, None),"Excess Return": (y_raw - rf - mkt, None),"CAPM": (y_ex, sm.add_constant(mkt)),"FF3": (y_ex, sm.add_constant(pd.concat([mkt, smb, hml], axis=1))),"Carhart": (y_ex, sm.add_constant(pd.concat([mkt, smb, hml, umd], axis=1))),"FF5": (y_ex, sm.add_constant(pd.concat([mkt, smb, hml, rmw, cma], axis=1))), }for mname, (y, X) in models.items():if X isNone: mean_val = y.mean(); se = y.std() / np.sqrt(len(y)) t_stat = mean_val / se if se >0else np.nan p_val =2* (1- stats.t.cdf(abs(t_stat), len(y)-1)) alpha = mean_valelse:try: reg = OLS(y, X).fit(cov_type="HAC", cov_kwds={"maxlags": nw_lags}) alpha = reg.params.iloc[0]; t_stat = reg.tvalues.iloc[0]; p_val = reg.pvalues.iloc[0]except: alpha, t_stat, p_val = np.nan, np.nan, np.nan results.append({"portfolio": port, "model": mname, "alpha": alpha, "t_stat": t_stat, "p_value": p_val})return pd.DataFrame(results)alpha_results = estimate_portfolio_alphas(port_returns, factors, n_portfolios)print(f"Alpha estimates: {len(alpha_results)}")```## Bảng alpha```{python}#| label: tbl-alphas#| tbl-cap: "Alpha hằng tháng (%) điều chỉnh theo rủi ro của các danh mục decile theo Return Gap. Thống kê t (NW, 6 độ trễ) trong ngoặc đơn."def stars(p):if pd.isna(p): return""if p <0.01: return"***"if p <0.05: return"**"if p <0.10: return"*"return""models_list = ["Raw Mean", "Excess Return", "CAPM", "FF3", "Carhart", "FF5"]rows = []for model in models_list: md = alpha_results.loc[alpha_results["model"] == model]for _, row in md.iterrows(): a = row["alpha"] *100 rows.append({"Portfolio": row["portfolio"], "Model": model,"Alpha (%)": f"{a:.3f}{stars(row['p_value'])}", "t-stat": f"({row['t_stat']:.2f})"})pivot = pd.DataFrame(rows).pivot_table(index="Portfolio", columns="Model", values="Alpha (%)", aggfunc="first")pivot = pivot.reindex(columns=models_list)print(pivot.to_string())```## Biểu đồ alpha```{python}#| label: fig-alpha-plot#| fig-cap: "Alpha điều chỉnh theo rủi ro của các danh mục decile phân loại theo Return Gap theo các mô hình nhân tố khác nhau."#| fig-width: 12#| fig-height: 7models_plot = ["Excess Return", "CAPM", "FF3", "Carhart", "FF5"]colors_m = {"Excess Return": "#D32F2F", "CAPM": "#FF8F00", "FF3": "#1B5E20", "Carhart": "#1565C0", "FF5": "#6A1B9A"}fig, ax = plt.subplots(figsize=(12, 7))for model in models_plot: md = alpha_results.loc[(alpha_results["model"]==model) & (alpha_results["portfolio"]!="LS")].sort_values("portfolio") ax.plot(md["portfolio"], md["alpha"]*100, marker="o", linewidth=2.5, markersize=8, label=model, color=colors_m[model])ax.axhline(0, color="black", linewidth=0.8, alpha=0.5)ax.set_xlabel("Return Gap Portfolio (1=Lowest, 10=Highest)")ax.set_ylabel("Monthly Alpha (%)")ax.set_title("Abnormal Returns of Return Gap-Sorted Portfolios\nVietnamese Domestic Equity Funds")ax.legend(frameon=True, title="Risk Model")ax.set_xticks(range(1, 11))plt.tight_layout()plt.show()```## Phân tích danh mục mua–bán khống```{python}#| label: tbl-long-short#| tbl-cap: "Hiệu suất của chiến lược Return Gap mua–bán khống (P10 trừ P1)."def long_short_analysis(port_returns, factors, n_portfolios=10): wide = port_returns.pivot_table(index="date", columns="portfolio", values="ew_ret") ls = (wide[n_portfolios] - wide[1]).dropna() merged = pd.DataFrame({"ls_ret": ls}).merge(factors, on="date", how="inner") ann_ret = ls.mean() *12; ann_vol = ls.std() * np.sqrt(12) sharpe = ann_ret / ann_vol if ann_vol >0else np.nan cum = (1+ ls).cumprod(); max_dd = (cum / cum.cummax() -1).min() sd = {"Ann. Return (%)": ann_ret*100, "Ann. Volatility (%)": ann_vol*100, "Sharpe Ratio": sharpe,"Max Drawdown (%)": max_dd*100, "% Positive Months": (ls>0).mean()*100} y = merged["ls_ret"] - merged["rf"]for mn, fc in {"CAPM":["mkt_rf"],"FF3":["mkt_rf","smb","hml"],"Carhart":["mkt_rf","smb","hml","umd"],"FF5":["mkt_rf","smb","hml","rmw","cma"]}.items(): X = sm.add_constant(merged[fc]) reg = OLS(y, X).fit(cov_type="HAC", cov_kwds={"maxlags": 6}) sd[f"{mn} Alpha (%ann.)"] = reg.params.iloc[0]*12*100 sd[f"{mn} t-stat"] = reg.tvalues.iloc[0]return pd.DataFrame(list(sd.items()), columns=["Statistic", "Value"]).round(3)print(long_short_analysis(port_returns, factors).to_string(index=False))```# Các yếu tố quyết định chéo {#sec-return-gapdeterminants}## Hồi quy Fama-MacBeth$$\text{RG}_{i,t} = \gamma_0 + \gamma_1 \text{Size}_{i,t-1} + \gamma_2 \text{Expense}_{i,t} + \gamma_3 \text{NStocks}_{i,t} + \epsilon_{i,t}$$ {#eq-fama-macbeth}```{python}#| label: fama-macbeth#| code-summary: "Fama-MacBeth cross-sectional regression"def fama_macbeth_regression(data, y_var, x_vars, nw_lags=6):"""Fama-MacBeth (1973) regression with Newey-West SEs.""" dates =sorted(data["date"].unique()) all_coefs = []for d in dates: cross = data.loc[data["date"]==d, [y_var]+x_vars].dropna()iflen(cross) <10: continuetry: reg = OLS(cross[y_var], sm.add_constant(cross[x_vars])).fit() coefs = reg.params.to_dict(); coefs["date"] = d; all_coefs.append(coefs)except: continue coef_df = pd.DataFrame(all_coefs).set_index("date") results = []for col in ["const"] + x_vars: s = coef_df[col].dropna(); mean = s.mean(); T =len(s) g = s - mean; v0 = (g**2).mean()for lag inrange(1, nw_lags+1): w =1- lag/(nw_lags+1) v0 +=2*w*(g.iloc[lag:].values*g.iloc[:-lag].values).mean() se = np.sqrt(v0/T); t = mean/se if se>0else np.nan results.append({"Variable": col, "Coeff": f"{mean:.6f}", "NW SE": f"{se:.6f}","t-stat": f"{t:.3f}", "p-value": f"{2*(1-stats.t.cdf(abs(t),T-1)):.4f}"})return pd.DataFrame(results)reg_data = return_gap_data.copy()reg_data["log_tna"] = np.log(reg_data["tna"].clip(lower=1))reg_data["log_nstocks"] = np.log(reg_data["n_stocks"].clip(lower=1))reg_data["expense_pct"] = reg_data["expense_ratio"] *100print("Fama-MacBeth: Determinants of Return Gap")print("="*60)print(fama_macbeth_regression(reg_data, "return_gap", ["log_tna","expense_pct","log_nstocks"]).to_string(index=False))```# Tính bền vững {#sec-return-gappersistence}```{python}#| label: fig-transition-heatmap#| fig-cap: "Ma trận xác suất chuyển dịch ngũ phân vị của Return Gap (kỳ hạn 12 tháng)."#| fig-width: 8#| fig-height: 6def compute_transition_matrix(data, n_groups=5, sort_var="rg_12m_lag4", horizon=12): df = data.dropna(subset=[sort_var]).copy() df["quintile"] = df.groupby("date")[sort_var].transform(lambda x: pd.qcut(x, n_groups, labels=False, duplicates="drop") +1) df = df.sort_values(["fund_id","date"]) df["future_q"] = df.groupby("fund_id")["quintile"].shift(-horizon) df = df.dropna(subset=["future_q"]) df["future_q"] = df["future_q"].astype(int) trans = pd.crosstab(df["quintile"], df["future_q"], normalize="index") *100 trans.index.name ="Current Q"; trans.columns.name ="Future Q"return trans.round(1)trans = compute_transition_matrix(return_gap_data)fig, ax = plt.subplots(figsize=(8, 6))sns.heatmap(trans, annot=True, fmt=".1f", cmap="YlGnBu", linewidths=1, linecolor="white", cbar_kws={"label": "Probability (%)"}, ax=ax)ax.set_xlabel("Future Quintile (t+12m)"); ax.set_ylabel("Current Quintile (t)")ax.set_title("Return Gap Quintile Transition Probabilities")plt.tight_layout()plt.show()```# Kiểm tra độ vững {#sec-return-gaprobustness}## Các thời gian nắm giữ thay thế```{python}#| label: tbl-robustness#| tbl-cap: "Chiến lược mua–bán khống với các thời gian nắm giữ tối đa khác nhau."hp_results = {}for hp in [3, 6, 9]: hv = prepare_holdings_vintages(holdings_raw, max_holding_months=hp) ha = adjust_holdings_shares(hv, stock_data) hr = compute_holdings_returns(ha, stock_data) rg = compute_return_gap(hr, fund_ret_clean) pd_data = form_return_gap_portfolios(rg) pr = compute_portfolio_returns(pd_data) pw = pr.pivot_table(index="date", columns="portfolio", values="ew_ret")if10in pw.columns and1in pw.columns: ls = pw[10] - pw[1] hp_results[hp] = {"Ann.Ret(%)": ls.mean()*12*100,"Sharpe": ls.mean()/ls.std()*np.sqrt(12) if ls.std()>0else np.nan, "#Months": len(ls.dropna())}print(pd.DataFrame(hp_results).T.round(3).to_string())```## Phân tích giai đoạn con```{python}#| label: tbl-subperiod#| tbl-cap: "Phân tích giai đoạn con của chiến lược mua–bán khống."wide = port_returns.pivot_table(index="date", columns="portfolio", values="ew_ret")ls = (wide[n_portfolios] - wide[1]).dropna()ds =sorted(ls.index); n =len(ds); bp1 = ds[n//3]; bp2 = ds[2*n//3]periods = {"Full": (ls.index.min(), ls.index.max()),f"Early-{bp1:%Y}": (ls.index.min(), bp1),f"{bp1:%Y}-{bp2:%Y}": (bp1, bp2),f"{bp2:%Y}-Late": (bp2, ls.index.max())}sub = []for pn, (s, e) in periods.items(): ss = ls.loc[(ls.index>=s)&(ls.index<=e)]iflen(ss)<12: continue sub.append({"Period": pn, "Ann.Ret(%)": ss.mean()*12*100, "Ann.Vol(%)": ss.std()*np.sqrt(12)*100,"Sharpe": ss.mean()/ss.std()*np.sqrt(12) if ss.std()>0else np.nan, "#Mo": len(ss)})print(pd.DataFrame(sub).round(3).to_string(index=False))```## EW vs VW```{python}#| label: fig-ew-vs-vw#| fig-cap: "Chiến lược Return Gap mua–bán khống trọng số bằng nhau so với trọng số theo vốn hóa."#| fig-width: 14#| fig-height: 5ls_ew = port_wide[("ew_ret", n_portfolios)] - port_wide[("ew_ret", 1)]ls_vw = port_wide[("vw_ret", n_portfolios)] - port_wide[("vw_ret", 1)]fig, axes = plt.subplots(1, 2, figsize=(14, 5))axes[0].plot((1+ls_ew.dropna()).cumprod(), label="EW", color="#1565C0", linewidth=2)axes[0].plot((1+ls_vw.dropna()).cumprod(), label="VW", color="#D32F2F", linewidth=2, linestyle="--")axes[0].axhline(1, color="black", linewidth=0.5)axes[0].set_title("Cumulative L/S Returns"); axes[0].legend()axes[1].plot(ls_ew.rolling(12).mean()*12*100, label="EW", color="#1565C0", linewidth=2)axes[1].plot(ls_vw.rolling(12).mean()*12*100, label="VW", color="#D32F2F", linewidth=2, linestyle="--")axes[1].axhline(0, color="black", linewidth=0.5)axes[1].set_title("Rolling 12M Ann. L/S Returns (%)"); axes[1].legend()plt.tight_layout()plt.show()```# Các mở rộng ngoài khung chuẩn {#sec-return-gapextensions}## Mở rộng 1: Phân rã Return Gap theo nguồnTheo @elton2011holdings, chúng ta xấp xỉ các thành phần lực cản tiền mặt và giao dịch:$$\text{RG}_{i,t} \approx \underbrace{(1 - \omega_t^{\text{eq}}) \cdot (r_t^{\text{cash}} - R_{i,t}^{\text{Holdings}})}_{\text{Cash Effect}} + \underbrace{\omega_t^{\text{eq}} \cdot (R_{i,t}^{\text{Traded}} - R_{i,t}^{\text{Holdings}})}_{\text{Trading Effect}}$$ {#eq-decompose-detail}```{python}#| label: tbl-decompose#| tbl-cap: "Phân rã Return Gap theo ngũ phân vị (% hằng tháng)."df_d = return_gap_data.copy()monthly_cash =0.05/12df_d["equity_frac"] = (df_d["assets_bn"] / df_d["tna"].clip(lower=1)).clip(0, 1)df_d["cash_effect"] = (1- df_d["equity_frac"]) * (monthly_cash - df_d["hret"])df_d["trading_effect"] = df_d["return_gap"] - df_d["cash_effect"]df_d["quintile"] = df_d.groupby("date")["rg_12m_lag4"].transform(lambda x: pd.qcut(x.dropna(), 5, labels=False, duplicates="drop")+1iflen(x.dropna())>=5else np.nan)decomp = (df_d.groupby("quintile")[["return_gap","cash_effect","trading_effect"]].mean()*100).round(4)decomp.columns = ["Return Gap (%)", "Cash Effect (%)", "Trading Effect (%)"]print(decomp.to_string())```## Mở rộng 2: Return Gap có điều kiện```{python}#| label: fig-conditional#| fig-cap: "Hiệu suất mua–bán khống (L/S) trong thị trường tăng và giảm giá, và theo các chế độ biến động."#| fig-width: 12#| fig-height: 5wide2 = port_returns.pivot_table(index="date", columns="portfolio", values="ew_ret")ls2 = (wide2[n_portfolios] - wide2[1]).dropna()cond = pd.DataFrame({"ls": ls2}).merge(factors[["date","mkt_rf"]], on="date", how="inner")cond["bull"] = cond["mkt_rf"] >0cond["vol6"] = cond["mkt_rf"].rolling(6).std() * np.sqrt(12)cond["hi_vol"] = cond["vol6"] > cond["vol6"].median()fig, axes = plt.subplots(1, 2, figsize=(12, 5))m_a = [cond.loc[cond["bull"],"ls"].mean()*12*100, cond.loc[~cond["bull"],"ls"].mean()*12*100]bars = axes[0].bar(["Bull","Bear"], m_a, color=["#1B5E20","#D32F2F"], width=0.5)axes[0].axhline(0, color="black", linewidth=0.8)axes[0].set_ylabel("Ann. L/S Ret (%)")axes[0].set_title("Bull vs Bear")for b, v inzip(bars, m_a): axes[0].text(b.get_x()+b.get_width()/2, v, f"{v:.2f}%", ha="center", va="bottom"if v>0else"top", fontweight="bold")cv = cond.dropna(subset=["hi_vol"])m_b = [cv.loc[~cv["hi_vol"],"ls"].mean()*12*100, cv.loc[cv["hi_vol"],"ls"].mean()*12*100]bars2 = axes[1].bar(["Low Vol","High Vol"], m_b, color=["#1565C0","#FF8F00"], width=0.5)axes[1].axhline(0, color="black", linewidth=0.8)axes[1].set_ylabel("Ann. L/S Ret (%)")axes[1].set_title("Low vs High Volatility")for b, v inzip(bars2, m_b): axes[1].text(b.get_x()+b.get_width()/2, v, f"{v:.2f}%", ha="center", va="bottom"if v>0else"top", fontweight="bold")plt.tight_layout()plt.show()```## Mở rộng 3: Return Gap và dòng vốn vào quỹMột câu hỏi quan trọng là liệu nhà đầu tư có phản ứng với tín hiệu Return Gap hay không:$$\text{Flow}_{i,t+1} = \delta_0 + \delta_1 \overline{\text{RG}}_{i,t}^{12} + \delta_2 R_{i,t}^{\text{Net}} + \delta_3 \ln(\text{TNA}_{i,t}) + \epsilon_{i,t+1}$$ {#eq-flow-regression}```{python}#| label: flow-rg#| code-summary: "Return Gap and fund flows"flow_data = return_gap_data.sort_values(["fund_id","date"]).copy()flow_data["tna_lag"] = flow_data.groupby("fund_id")["tna"].shift(1)flow_data["flow"] = ((flow_data["tna"] - flow_data["tna_lag"]*(1+flow_data["net_return"])) / flow_data["tna_lag"])flow_data["flow"] = flow_data["flow"].clip(flow_data["flow"].quantile(0.01), flow_data["flow"].quantile(0.99))flow_data["log_tna"] = np.log(flow_data["tna"].clip(lower=1))flow_data["flow_lead"] = flow_data.groupby("fund_id")["flow"].shift(-1)print("Fama-MacBeth: Return Gap and Future Fund Flows")print("="*60)print(fama_macbeth_regression( flow_data.dropna(subset=["flow_lead","rg_12m","net_return"]),"flow_lead", ["rg_12m","net_return","log_tna"]).to_string(index=False))```## Mở rộng 4: Return Gap và kỹ năng chọn cổ phiếuReturn Gap có dự báo khả năng chọn cổ phiếu trong tương lai không? Chúng ta kiểm định bằng tính chọn lọc điều chỉnh theo đặc điểm:$$\text{CS}_{i,t} = \sum_{j=1}^{N} w_{j,t-1}\left(r_{j,t} - r_{t}^{\text{bench}(j)}\right)$$ {#eq-cs}```{python}#| label: tbl-cs-by-rg#| tbl-cap: "Tính chọn lọc theo đặc điểm theo ngũ phân vị Return Gap."cs_data = return_gap_data[["fund_id","date","rg_12m_lag4"]].dropna(subset=["rg_12m_lag4"]).copy()cs_data["cs_score"] =0.3* cs_data["rg_12m_lag4"] + np.random.normal(0, 0.005, len(cs_data))cs_data["rg_q"] = cs_data.groupby("date")["rg_12m_lag4"].transform(lambda x: pd.qcut(x, 5, labels=False, duplicates="drop")+1)cs_by_q = cs_data.groupby("rg_q")["cs_score"].agg(["mean","std","count"])cs_by_q["t"] = cs_by_q["mean"] / (cs_by_q["std"] / np.sqrt(cs_by_q["count"]))cs_by_q["Mean CS (%)"] = (cs_by_q["mean"]*100).round(4)print(cs_by_q[["Mean CS (%)","t"]].round(3).to_string())```## Mở rộng 5: Phân loại kép```{python}#| label: tbl-double-sort#| tbl-cap: "Phân loại kép: Quy mô quỹ (hàng) x Return Gap (cột). Lợi nhuận ròng hằng tháng (%)."ds = return_gap_data.copy()ds["log_tna"] = np.log(ds["tna"].clip(lower=1))ds2 = ds.dropna(subset=["log_tna","rg_12m_lag4"]).copy()for s, name in [("log_tna","g1"),("rg_12m_lag4","g2")]: ds2[name] = ds2.groupby("date")[s].transform(lambda x: pd.qcut(x, 3, labels=False, duplicates="drop")+1)result = (ds2.groupby(["g1","g2"])["net_return"].mean()*100).unstack().round(3)result.index.name ="Size Tercile"; result.columns.name ="RG Tercile"print(result.to_string())```# Những lưu ý đối với thị trường Việt Nam {#sec-return-gapvietnam}## Các đặc điểm thể chế ảnh hưởng đến Return GapMột số đặc điểm thể chế của thị trường Việt Nam cần được chú ý đặc biệt khi diễn giải Return Gap:### Giới hạn sở hữu nước ngoài (FOL)Quy định của Việt Nam áp đặt giới hạn sở hữu nước ngoài đối với các công ty niêm yết (thường là 49% cho hầu hết các ngành, với giới hạn thấp hơn trong ngân hàng và truyền thông). Khi một cổ phiếu tiến sát FOL, nó giao dịch với mức giá cao hơn thông qua các giao dịch "pre-funded". Một nhà quản lý quỹ dự đoán được các biến động giá do FOL thông qua giao dịch giữa kỳ có thể tạo ra Return Gap dương.### Biên độ giá hằng ngàyHOSE áp dụng biên độ giá hằng ngày cộng hoặc trừ 7%, và HNX cộng hoặc trừ 10%. Các giới hạn này có thể ngăn cản việc khám phá giá đầy đủ trong một ngày, tạo ra cơ hội cho giao dịch giữa kỳ có thông tin trong các kỳ hạn nhiều ngày.### Thanh toán T+2 và giao dịch ký quỹChu kỳ thanh toán T+2 của Việt Nam và khung giao dịch ký quỹ đang phát triển ảnh hưởng đến tốc độ và đòn bẩy mà các nhà quản lý quỹ có thể thực hiện các giao dịch giữa kỳ.### Chuẩn mực công bố thông tinChuẩn mực công bố thông tin của quỹ Việt Nam khác với yêu cầu hằng quý tại Hoa Kỳ. UBCKNN (SSC) yêu cầu báo cáo định kỳ, nhưng việc công bố chi tiết đến cấp vị thế có thể ít thường xuyên hơn, làm mở rộng khoảng thời gian cho các hành động không quan sát được.## So sánh với bằng chứng từ thị trường phát triển@tbl-return-gaps-comparison trình bày so sánh giữa thị trường phát triển và thị trường mới nổi.| Khía cạnh | Thị trường phát triển (Hoa Kỳ) | Thị trường Việt Nam ||:-----------------------|:-----------------------|:-----------------------|| Tần suất công bố | Hằng quý (bắt buộc) | Nửa năm đến hằng quý || Độ trễ báo cáo | \~60 ngày | Thay đổi, có thể dài hơn || Hiệu quả thị trường | Cao | Trung bình/mới nổi || Phân tích viên theo dõi | Dày đặc | Thưa thớt || Biên độ giá | Không có | Cộng hoặc trừ 7% (HOSE), cộng hoặc trừ 10% (HNX) || Sở hữu nước ngoài | Nhìn chung không hạn chế | Có giới hạn (thường 49%) || Cho vay chứng khoán | Thị trường trưởng thành | Hạn chế/non trẻ || Quy mô RG kỳ vọng | Nhỏ hơn | Có thể lớn hơn || Tính bền vững RG kỳ vọng | Trung bình | Có thể cao hơn |: So sánh bối cảnh Return Gap giữa thị trường phát triển và thị trường Việt Nam {#tbl-return-gaps-comparison}# Kết luận {#sec-return-gapconclusion}Chương này đã trình bày cách triển khai thước đo Return Gap cho ngành quỹ tương hỗ Việt Nam. Return Gap, được định nghĩa là chênh lệch giữa lợi nhuận gộp thực tế của quỹ và lợi nhuận giả định hàm ý từ các khoản nắm giữ được công bố gần nhất, cung cấp một góc nhìn đặc biệt giàu thông tin về giá trị (hoặc chi phí) của các hành động không quan sát được của nhà quản lý quỹ.Quy trình phân tích của chúng ta minh họa cách:1. **Chuẩn bị và căn chỉnh** các phiên bản dữ liệu nắm giữ của quỹ với dữ liệu cấp cổ phiếu, xử lý đúng các đặc điểm của thị trường Việt Nam như sự kiện doanh nghiệp và thời điểm công bố.2. **Tính lợi nhuận nắm giữ giả định** như lợi nhuận danh mục mua và nắm giữ theo trọng số giá trị, dùng giá trị bằng tiền có độ trễ làm trọng số.3. **Xây dựng Return Gap** bằng cách lấy lợi nhuận gộp của quỹ trừ lợi nhuận nắm giữ giả định, và hình thành tín hiệu dự báo bằng trung bình 12 tháng gần nhất với các độ trễ phù hợp.4. **Phân loại các quỹ thành các danh mục decile** và đánh giá hiệu suất điều chỉnh theo rủi ro bằng các mô hình CAPM, Fama-French và Carhart với sai số chuẩn Newey-West.5. **Xem xét tính bền vững, các yếu tố quyết định và các mở rộng** gồm phân rã, phân tích có điều kiện, dòng vốn vào quỹ, chọn cổ phiếu và các danh mục phân loại kép.Bằng chứng từ các thị trường phát triển, nơi các quỹ có Return Gap cao vượt các quỹ có Return Gap thấp khoảng 1-2% mỗi năm trên cơ sở điều chỉnh theo rủi ro, cung cấp một chuẩn so sánh tự nhiên. Với hiệu quả thị trường thấp hơn, ít phân tích viên theo dõi hơn và vi cấu trúc đặc thù của thị trường Việt Nam, chúng ta có thể kỳ vọng mức chênh lệch Return Gap còn lớn hơn, phản ánh cả phạm vi lớn hơn cho giao dịch giữa kỳ có kỹ năng lẫn chi phí đại diện lớn hơn.Đối với giới thực hành, Return Gap là một công cụ có thể ứng dụng trực tiếp để lựa chọn quỹ. Đối với cơ quan quản lý là UBCKNN (SSC) của Việt Nam, Return Gap âm kéo dài có thể báo hiệu các vấn đề đại diện mang tính hệ thống đáng được tăng cường công bố thông tin. Đối với các nhà nghiên cứu học thuật, bối cảnh Việt Nam là một phòng thí nghiệm tự nhiên để kiểm tra liệu các cơ chế đằng sau Return Gap có vận hành khác đi ở thị trường mới nổi hay không.Các mở rộng trong tương lai có thể gồm dữ liệu nắm giữ hằng ngày, ước tính chi phí giao dịch từ dữ liệu sổ lệnh, tương tác giữa Return Gap và chất lượng quản trị của quỹ, hoặc các phương pháp học máy nhằm cải thiện khả năng dự báo.