Một câu hỏi nền tảng của kinh tế học tài chính là sự khác biệt về niềm tin của nhà đầu tư ảnh hưởng thế nào đến giá tài sản và hoạt động giao dịch. Trong các thị trường mà nhà đầu tư có kỳ vọng không đồng nhất về dòng tiền tương lai của doanh nghiệp, việc tổng hợp những quan điểm phân kỳ này thành một mức giá thị trường duy nhất là một bài toán không đơn giản, với những hàm ý sâu sắc đối với định giá tài sản, khả năng dự báo lợi nhuận và tính hiệu quả của thị trường. Khái niệm sự phân kỳ quan điểm của nhà đầu tư (sau đây viết tắt là DIVOP) đã trở thành một khái niệm trung tâm trong cả các nghiên cứu kế toán lẫn tài chính, đóng vai trò như một lăng kính để các nhà nghiên cứu xem xét môi trường thông tin của doanh nghiệp, động lực của việc giải tỏa bất định, và bản chất của phản ứng thị trường trước tin tức.
Nền tảng lý thuyết của các nghiên cứu về DIVOP bắt nguồn từ Miller (1977), người đề xuất rằng khi các nhà đầu tư bất đồng về giá trị của một chứng khoán và các hạn chế bán khống ngăn cản các nhà đầu tư bi quan thể hiện đầy đủ quan điểm của mình, thì giá thị trường sẽ phản ánh mức định giá của những nhà đầu tư lạc quan nhất. Điều này dẫn đến tình trạng định giá quá cao có hệ thống, tăng theo mức độ phân kỳ quan điểm. Tình trạng định giá quá cao kéo dài cho đến khi các sự kiện thông tin, chẳng hạn như công bố lợi nhuận, làm giảm bất đồng và giá hội tụ về giá trị cơ bản (Berkman và c.s. 2009). Varian (1985) đưa ra một góc nhìn khác, trong đó sự phân kỳ quan điểm là một yếu tố rủi ro bổ sung, dẫn đến lợi nhuận kỳ vọng cao hơn chứ không phải thấp hơn, tạo ra một sự giằng co lý thuyết đã thúc đẩy nhiều nghiên cứu thực nghiệm.
Các nghiên cứu thực nghiệm về DIVOP đã mở rộng đáng kể kể từ những đóng góp nền tảng này. Các nhà nghiên cứu đã ghi nhận rằng sự phân kỳ quan điểm giúp giải thích một loạt hiện tượng bất thường trong định giá tài sản, bao gồm hiện tượng trôi dạt sau công bố lợi nhuận (Garfinkel và Sokobin 2006; K. L. Anderson, Harris, và So 2007), chênh lệch lợi nhuận mặt cắt ngang giữa cổ phiếu giá trị và cổ phiếu tăng trưởng (Doukas, Kim, và Pantzalis 2004), lợi nhuận ngắn hạn và dài hạn sau IPO (Houge và c.s. 2001), lợi nhuận cổ phiếu trước và sau thương vụ mua lại (Alexandridis, Antoniou, và Petmezas 2007), phần bù thâu tóm (Chatterjee, John, và Yan 2012), và mặt cắt ngang rộng của lợi nhuận cổ phiếu (Diether, Malloy, và Scherbina 2002; Doukas, Kim, và Pantzalis 2006). Sức giải thích của DIVOP đã được chứng minh bằng một tập hợp phong phú các biến đại diện thực nghiệm, từ mức phân tán dự báo của nhà phân tích và khối lượng giao dịch bất thường đến chênh lệch giá mua–bán và biến động đặc thù.
Mặc dù các nghiên cứu về DIVOP đã chín muồi ở các thị trường phát triển, đặc biệt là Hoa Kỳ, việc áp dụng vào các thị trường mới nổi vẫn còn rất mỏng. Khoảng trống này đặc biệt đáng chú ý vì các điều kiện lý thuyết khiến sự phân kỳ quan điểm quan trọng nhất (cụ thể là các hạn chế bán khống có hiệu lực ràng buộc, bất cân xứng thông tin, và mức độ tinh vi không đồng đều của nhà đầu tư) có thể nói là phổ biến hơn ở các thị trường mới nổi so với các thị trường phát triển. Thị trường chứng khoán Việt Nam là một phòng thí nghiệm hấp dẫn để nghiên cứu sự bất đồng của nhà đầu tư. Thị trường này có một số đặc điểm làm gia tăng tính phù hợp của khung phân tích DIVOP:
Hạn chế bán khống có hiệu lực ràng buộc. Bán khống không được phép ở Việt Nam cho đến tháng 1 năm 2025, và ngay cả sau khi được đưa vào, cơ chế này vẫn chỉ giới hạn ở một nhóm chứng khoán hạn chế với những ràng buộc quản lý đáng kể về việc thực hiện. Điều này phản ánh sát bối cảnh lý thuyết của Miller (1977), nơi các nhà đầu tư bi quan không thể thể hiện đầy đủ quan điểm của mình thông qua các vị thế bán khống.
Sự áp đảo của nhà đầu tư cá nhân. Nhà đầu tư cá nhân chiếm khoảng 80-85% khối lượng giao dịch hằng ngày trên HOSE và HNX, so với khoảng 25% ở Hoa Kỳ. Nhà đầu tư cá nhân dễ chịu tác động hơn của các thiên lệch hành vi, giao dịch theo tâm lý và các hạn chế trong xử lý thông tin, vốn tự nhiên làm nảy sinh niềm tin không đồng nhất (Phan và c.s. 2023).
Bất cân xứng thông tin và thách thức về minh bạch. Mặc dù các chuẩn mực công bố thông tin đã được cải thiện, khuôn khổ quản lý báo cáo doanh nghiệp của Việt Nam vẫn kém chặt chẽ hơn so với các thị trường phát triển. Việc công bố thông tin có chọn lọc, nộp báo cáo tài chính chậm trễ, và việc thực thi hạn chế các quy định về giao dịch nội gián tạo ra một môi trường trong đó các nhà đầu tư hoạt động với những tập thông tin khác biệt đáng kể (Vo và Phan 2017).
Giới hạn sở hữu nước ngoài. Mức trần sở hữu nước ngoài (hiện là 49% đối với hầu hết các ngành, có một số ngoại lệ) tạo ra một thị trường bị phân khúc, trong đó nhà đầu tư trong nước và nước ngoài có thể có những quan điểm khác nhau một cách có hệ thống về giá trị doanh nghiệp, làm gia tăng sự phân kỳ quan điểm.
Độ phủ của nhà phân tích còn mỏng. Trong khi một doanh nghiệp S&P 500 điển hình được 15-25 nhà phân tích bên bán theo dõi, độ phủ đối với cổ phiếu Việt Nam tập trung ở một số ít công ty môi giới trong nước và một vài đơn vị nghiên cứu quốc tế. Điều này làm hạn chế tính thông tin của các thước đo DIVOP truyền thống dựa trên nhà phân tích và đòi hỏi phải dựa nhiều hơn vào các biến đại diện dựa trên thị trường.
Chương này trình bày một phương pháp xây dựng nhiều biến đại diện cho sự phân kỳ quan điểm của nhà đầu tư, được điều chỉnh theo các đặc điểm thể chế của thị trường Việt Nam. Chúng ta dựa trên các khung phương pháp luận do Garfinkel (2009) và Diether, Malloy, và Scherbina (2002) thiết lập, đồng thời đưa vào những điều chỉnh phản ánh vi cấu trúc của các sàn giao dịch Việt Nam, chu kỳ thanh toán \(T+2\), việc không có bán khống (cho đến gần đây), và khả năng tiếp cận dữ liệu qua các nền tảng tài chính trong nước. Cụ thể, chúng ta xây dựng và phân tích các biến đại diện DIVOP sau:
Khối lượng không được giải thích (DTO): Vòng quay đã điều chỉnh theo thị trường và loại bỏ xu hướng bằng trung vị trượt, nắm bắt hoạt động giao dịch bất thường do bất đồng quan điểm sau khi kiểm soát các hiệu ứng thanh khoản và hiệu ứng toàn thị trường.
Khối lượng không được giải thích đã chuẩn hóa (SUV): Một thước đo dựa trên hồi quy, kiểm soát một cách tường minh các thành phần thông tin và thanh khoản của khối lượng bằng cách mô hình hóa vòng quay như một hàm của lợi nhuận có dấu.
Biến động lợi nhuận cổ phiếu (VOLATILITY): Độ lệch chuẩn của lợi nhuận hằng ngày trong một cửa sổ ước lượng trượt, đóng vai trò biến đại diện cho mức phân tán trong định giá của nhà đầu tư.
Chênh lệch giá mua–bán (BASPREAD): Chênh lệch giá chào theo tỷ lệ, phản ánh thành phần lựa chọn bất lợi gắn với thông tin không đồng nhất giữa các thành viên thị trường.
Phân tán dự báo của nhà phân tích (DISP): Độ lệch chuẩn mặt cắt ngang của các dự báo lợi nhuận của từng nhà phân tích, đo lường trực tiếp sự bất đồng giữa các thành viên thị trường có thông tin.
Biến động đặc thù (IVOL): Biến động phần dư từ hồi quy mô hình nhân tố, tách riêng thành phần đặc thù của doanh nghiệp trong biến thiên lợi nhuận, phản ánh những cách diễn giải khác nhau của nhà đầu tư về thông tin cấp doanh nghiệp.
Phi thanh khoản Amihud (ILLIQ): Tỷ số tác động giá do Amihud (2002) đề xuất, nắm bắt khía cạnh bất cân xứng thông tin của sự bất đồng thông qua phản ứng giá đối với dòng lệnh.
Với mỗi biến đại diện, chúng ta mô tả động cơ lý thuyết, yêu cầu về dữ liệu, phương pháp xây dựng được điều chỉnh cho dữ liệu Việt Nam, các tính chất thực nghiệm quan sát được trong mặt cắt ngang của thị trường Việt Nam, và những lưu ý thực tiễn mà các nhà nghiên cứu cần ghi nhớ khi sử dụng các thước đo này. Chúng ta đặc biệt chú ý đến các vấn đề riêng của thị trường mới nổi, bao gồm giao dịch thưa thớt, điều chỉnh hành động doanh nghiệp, các hiệu ứng vi cấu trúc đặc thù của từng sàn, và sự tương tác giữa các ràng buộc sở hữu nước ngoài với các thước đo bất đồng của nhà đầu tư.
33 Khung lý thuyết
33.1 Giả thuyết định giá quá cao của Miller (1977)
Mô hình kinh điển về sự phân kỳ quan điểm và định giá tài sản bắt đầu từ Miller (1977). Nhận định trung tâm của Miller rất đơn giản: trong một thị trường mà nhà đầu tư có niềm tin không đồng nhất về các khoản chi trả tương lai của một tài sản rủi ro và các hạn chế bán khống ngăn một số nhà đầu tư hành động theo quan điểm bi quan, giá cân bằng sẽ do nhóm nhà đầu tư lạc quan nhất về giá trị tài sản quyết định. Mức độ định giá quá cao tăng theo cả mức độ phân kỳ quan điểm lẫn độ nghiêm ngặt của các hạn chế bán khống. Về mặt hình thức, nếu nhà đầu tư \(i\) gán cho một chứng khoán mức định giá \(V_i\), giá thị trường \(P\) thỏa mãn:
\[
P = E[V_i \mid V_i \geq V^*]
\]
trong đó \(V^*\) là mức định giá của nhà đầu tư biên, vượt quá mức định giá trung bình không điều kiện \(E[V_i]\) bất cứ khi nào các hạn chế bán khống có hiệu lực ràng buộc đối với một số nhà đầu tư. Mức độ định giá quá cao là:
đại lượng này dương và tăng theo độ phân tán của phân phối \(V_i\) (tức là sự phân kỳ quan điểm) và theo \(V^*\) (tức là mức nghiêm ngặt của các hạn chế bán khống).
Mô hình của Miller đưa ra một số dự đoán có thể kiểm định:
Dự đoán theo mặt cắt ngang: Các cổ phiếu có mức phân kỳ quan điểm cao hơn sẽ có lợi nhuận thấp hơn ở các giai đoạn sau khi giá dần điều chỉnh về giá trị cơ bản.
Dự đoán theo chuỗi thời gian: Các sự kiện thông tin làm giảm bất đồng (ví dụ: công bố lợi nhuận) sẽ gắn với lợi nhuận bất thường âm đối với các cổ phiếu có DIVOP cao, vì “phần bù lạc quan” tan biến.
Dự đoán về tương tác: Hiệu ứng định giá quá cao sẽ mạnh nhất ở các cổ phiếu đồng thời có mức phân kỳ quan điểm cao và chịu hạn chế bán khống có hiệu lực ràng buộc.
33.2 Các góc nhìn lý thuyết thay thế
Varian (1985) đề xuất một khung thay thế trong đó sự phân kỳ quan điểm đóng vai trò một yếu tố rủi ro. Nếu nhà đầu tư né tránh rủi ro và sự bất đồng phản ánh sự bất định thực sự về các khoản chi trả tương lai, thì mức phân tán niềm tin cao hơn sẽ gắn với lợi nhuận kỳ vọng cao hơn như một khoản bù đắp cho việc gánh thêm rủi ro. Điều này tạo ra một sự đối lập thực nghiệm rõ nét: giả thuyết Miller dự đoán mối quan hệ DIVOP-lợi nhuận mang dấu âm, trong khi mô hình Varian dự đoán mối quan hệ mang dấu dương.
Sự phân biệt giữa các lý thuyết này phụ thuộc then chốt vào vi cấu trúc thị trường và bối cảnh thể chế (@tbl-divop-theories).
Bảng 33.1: Tóm tắt các dự đoán lý thuyết về quan hệ DIVOP-lợi nhuận dưới các giả định khác nhau
Hong và Stein (2003) mở rộng khung của Miller bằng cách đưa vào sự lan tỏa thông tin dần dần. Trong mô hình của họ, thông tin tiêu cực được phản ánh vào giá chậm hơn thông tin tích cực vì các hạn chế bán khống làm tăng chi phí hành động theo quan điểm bi quan. Điều này tạo ra các mô thức giống động lượng, trong đó các cổ phiếu có DIVOP cao có lợi nhuận ngắn hạn dương (khi những người lạc quan đẩy giá lên) rồi đến lợi nhuận dài hạn âm (khi thông tin tiêu cực cuối cùng cũng đến được thị trường).
Scheinkman và Xiong (2003) đưa thêm một chiều mới khi lưu ý rằng khi nhà đầu tư tự tin thái quá về tín hiệu riêng và các hạn chế bán khống có hiệu lực ràng buộc, giá cổ phiếu chứa một thành phần “bong bóng đầu cơ” phản ánh giá trị quyền chọn của việc bán lại tài sản cho một nhà đầu tư tương lai có thể còn lạc quan hơn. Mô hình này dự đoán rằng cả khối lượng giao dịch cao lẫn biến động giá cao đều gắn với tình trạng định giá quá cao, tạo cơ sở lý thuyết cho việc sử dụng các biến đại diện DIVOP dựa trên khối lượng và dựa trên biến động.
33.3 Mức độ liên quan đối với thị trường Việt Nam
Thị trường chứng khoán Việt Nam cung cấp một bối cảnh đặc biệt sạch để kiểm định giả thuyết Miller. Thị trường chứng khoán Việt Nam vận hành mà không có bất kỳ cơ chế bán khống nào từ khi thành lập năm 2000 cho đến tháng 1 năm 2025, tức là suốt một phần tư thế kỷ, trong đó điều kiện cần đầu tiên của mô hình Miller (hạn chế bán khống có hiệu lực ràng buộc) được thỏa mãn bởi quy định chứ không phải do các ma sát thị trường. Ngay cả sau khi đưa vào bán khống có bảo đảm năm 2025, cơ chế này vẫn chỉ giới hạn ở các chứng khoán đáp ứng ngưỡng cụ thể về thanh khoản và vốn hóa thị trường, và môi trường quản lý đặt ra các yêu cầu vay mượn làm tăng đáng kể chi phí bán khống so với các thị trường phát triển.
Sự áp đảo của nhà đầu tư cá nhân làm khuếch đại điều kiện cần thứ hai (tức là niềm tin không đồng nhất). Các nghiên cứu về thị trường Việt Nam đã ghi nhận hành vi bầy đàn đáng kể (Vo và Phan 2017; Vo 2015), giao dịch theo tâm lý (Phan và c.s. 2023; Nguyen và Pham 2018), và bất cân xứng thông tin giữa nhà đầu tư trong nước và nước ngoài (Vo 2017). Những đặc điểm hành vi này tự nhiên tạo ra mức phân tán trong định giá của nhà đầu tư rộng hơn so với các thị trường do nhà đầu tư tổ chức chi phối, vốn có khả năng tiếp cận các khung phân tích và nguồn thông tin tương tự nhau.
Bảng 33.2 so sánh các đặc điểm thể chế chủ chốt liên quan đến khung DIVOP giữa Việt Nam và Hoa Kỳ.
Bảng 33.2: So sánh thể chế giữa Việt Nam và Hoa Kỳ liên quan đến sự phân kỳ quan điểm
Đặc điểm
Việt Nam (HOSE/HNX)
Hoa Kỳ (NYSE/NASDAQ)
Bán khống
Áp dụng từ tháng 1/2025 (hạn chế)
Được phép (Reg SHO từ 2005)
Tỷ trọng nhà đầu tư cá nhân trong khối lượng
~80-85%
~25%
Chu kỳ thanh toán
T+2 (dự kiến T+1 vào 2026)
T+1 (từ tháng 5/2024)
Biên độ giá hằng ngày
\(\pm\) 7% (HOSE), \(\pm\) 10% (HNX)
Không có
Mức trần sở hữu nước ngoài
49% (hầu hết các ngành)
Không có
Độ phủ nhà phân tích trung bình (VN30)
5-10 nhà phân tích
15-25 nhà phân tích
Báo cáo hằng quý bắt buộc
Có (từ 2012)
Có
Thị trường quyền chọn/phái sinh
Hợp đồng tương lai VN30 (từ 2017)
Quyền chọn/hợp đồng tương lai phong phú
Biên độ giá hằng ngày (\(\pm\) 7% trên HOSE và \(\pm\) 10% trên HNX) tạo ra một cơ chế bổ sung làm khuếch đại sự phân kỳ quan điểm. Khi một cổ phiếu chạm biên độ giá, các nhà đầu tư muốn giao dịch theo hướng của biên độ không thể thực hiện được, dẫn đến lệnh chưa khớp tích tụ và việc khám phá giá bị trì hoãn. Đặc điểm thể chế này có thể tạo ra các đỉnh nhọn ngắn hạn trong DIVOP đo được, phản ánh ma sát do biên độ gây ra chứ không phải sự bất đồng thực sự. Chúng ta xử lý vấn đề này trong phương pháp thực nghiệm bằng cách đánh dấu các ngày chạm biên độ và thực hiện các kiểm tra độ vững loại trừ những quan sát này.
34 Nguồn dữ liệu và xây dựng mẫu
34.1 Nguồn dữ liệu
Việc xây dựng các biến đại diện DIVOP cho thị trường Việt Nam đòi hỏi dữ liệu giao dịch cổ phiếu hằng ngày và, đối với các thước đo phân tán của nhà phân tích, dữ liệu dự báo của từng nhà phân tích. Chúng ta lấy toàn bộ dữ liệu từ DataCore.vn, nguồn cung cấp độ phủ của mọi chứng khoán niêm yết trên HOSE, HNX và sàn UPCoM (Unlisted Public Company Market). Bảng 34.1 tóm tắt các bộ dữ liệu và biến chính được dùng trong nghiên cứu này.
Bảng 34.1: Nguồn dữ liệu và các biến chính để xây dựng biến đại diện DIVOP
Bộ dữ liệu
Biến chính
Tần suất
Giao dịch cổ phiếu hằng ngày
Giá đóng cửa, giá cao nhất, giá thấp nhất, giá mở cửa, khối lượng, số cổ phiếu đang lưu hành, giá điều chỉnh, giá mua, giá bán
Hằng ngày
Hành động doanh nghiệp
Cổ tức, chia tách cổ phiếu, cổ phiếu thưởng, phát hành quyền mua
Theo sự kiện
Thông tin doanh nghiệp
Mã sàn, phân loại ngành (ICB), ngày niêm yết, ngày hủy niêm yết
Tĩnh/Định kỳ
Dự báo của nhà phân tích
Dự báo EPS của từng nhà phân tích, ngày công bố, ngày kết thúc kỳ tài chính, mã nhà phân tích, tên công ty môi giới
Theo từng dự báo
Chỉ số thị trường
Lợi nhuận hằng ngày của VN-Index, VN30, HNX-Index
Hằng ngày
Sở hữu nước ngoài
Khối lượng mua/bán của nhà đầu tư nước ngoài, tỷ lệ sở hữu nước ngoài, room ngoại còn lại
Hằng ngày
34.2 Xây dựng mẫu
Chúng ta xây dựng mẫu bằng các bộ lọc sau, áp dụng tuần tự:
Sample construction and initial data loading
import pandas as pdimport numpy as npfrom datetime import datetime, timedeltafrom sklearn.linear_model import LinearRegressionfrom scipy import stats as scipy_statsimport matplotlib.pyplot as pltimport matplotlib.dates as mdatesimport seaborn as snsimport warningswarnings.filterwarnings('ignore')# =============================================================================# Configuration Parameters# =============================================================================# Users can modify these parameters to adjust the methodologyCONFIG = {# Sample period'beg_date': '2007-01-01','end_date': '2024-12-31',# Estimation windows (in trading days)'est_window': 60, # Rolling window for SUV and volatility'detrend_window': 180, # Window for DTO detrending median'lag': 7, # Lag for DTO detrending'gap': 5, # Gap between estimation period and event date# Filters'min_price': 1000, # Minimum price in VND'min_volume_days': 0.8, # Min fraction of non-zero volume days in window'min_analysts': 3, # Minimum number of analysts for DISP'max_spread_pct': 0.50, # Maximum bid-ask spread as fraction of midpoint'forecast_carry_days': 105,# Days to carry forward stale analyst forecasts# Exchange identifiers'exchanges': ['HOSE', 'HNX'],# Price limit thresholds (for flagging)'price_limit_hose': 0.07,'price_limit_hnx': 0.10,}print("Configuration parameters loaded successfully.")print(f"Sample period: {CONFIG['beg_date']} to {CONFIG['end_date']}")print(f"Estimation window: {CONFIG['est_window']} trading days")print(f"Detrending window: {CONFIG['detrend_window']} trading days")
Configuration parameters loaded successfully.
Sample period: 2007-01-01 to 2024-12-31
Estimation window: 60 trading days
Detrending window: 180 trading days
Tập mẫu bao gồm mọi cổ phiếu phổ thông niêm yết trên HOSE và HNX trong giai đoạn từ tháng 1 năm 2007 đến tháng 12 năm 2024. Chúng ta bắt đầu từ năm 2007 thay vì từ khi thị trường hình thành (2000 đối với HOSE, 2005 đối với HNX) vì hai lý do. Thứ nhất, những năm đầu của thị trường Việt Nam có số doanh nghiệp niêm yết cực nhỏ (dưới 30 doanh nghiệp trên HOSE cho đến năm 2005), khiến phân tích mặt cắt ngang không đáng tin cậy. Thứ hai, chất lượng và tính nhất quán của dữ liệu cải thiện đáng kể sau đợt mở rộng thị trường 2006-2007, trong đó số doanh nghiệp niêm yết trên HOSE tăng từ khoảng 40 lên hơn 100.
Chúng ta áp dụng các bộ lọc sau để xây dựng mẫu phân tích:
Bộ lọc loại chứng khoán. Chúng ta chỉ giữ lại cổ phiếu phổ thông, loại trừ cổ phiếu ưu đãi, quỹ hoán đổi danh mục (ETF), chứng quyền có bảo đảm và chứng chỉ tiền gửi. Điều này tương tự bộ lọc chuẩn trong các nghiên cứu ở Hoa Kỳ, vốn giới hạn ở mã cổ phiếu CRSP 10 và 11.
Bộ lọc sàn giao dịch. Chúng ta đưa vào các cổ phiếu niêm yết trên HOSE và HNX nhưng loại trừ các chứng khoán UPCoM trong phân tích cơ sở. UPCoM là địa điểm giao dịch dựa trên đăng ký, với yêu cầu niêm yết ít chặt chẽ hơn và thanh khoản thấp hơn đáng kể, có thể đưa nhiễu vào các thước đo dựa trên khối lượng và chênh lệch giá. Chúng ta đưa UPCoM vào các kiểm tra độ vững.
Bộ lọc giá. Chúng ta loại trừ các quan sát cổ phiếu-ngày có giá đóng cửa dưới 1,000 VND. Ngưỡng này phục vụ cùng mục đích với việc loại trừ “cổ phiếu penny” phổ biến trong các nghiên cứu ở Hoa Kỳ (thường là ngưỡng $1 hoặc $5) và giúp giảm ảnh hưởng của lợi nhuận phần trăm và chênh lệch giá cực đoan ở các mức giá rất thấp.
Hoạt động giao dịch tối thiểu. Với các thước đo dựa trên khối lượng, chúng ta yêu cầu cổ phiếu có khối lượng giao dịch khác không trong ít nhất 80% số ngày giao dịch của mỗi cửa sổ ước lượng. Bộ lọc này loại bỏ những chứng khoán giao dịch thưa thớt nhất, vốn khiến các thước đo dựa trên vòng quay không đáng tin cậy.
Load and filter daily stock data
def load_daily_data(config):""" Load daily stock trading data from DataCore.vn. In practice, this function connects to the DataCore API or reads from a local database/CSV. Here we document the expected schema. Expected columns: - ticker: str, stock ticker symbol (e.g., 'VCB', 'HPG', 'VNM') - date: datetime, trading date - open, high, low, close: float, daily OHLC prices (VND) - volume: int, trading volume (shares) - shares_outstanding: int, total shares outstanding - adjusted_close: float, price adjusted for corporate actions - adj_factor: float, cumulative adjustment factor - bid, ask: float, best bid/ask at close - exchange: str, exchange code ('HOSE', 'HNX', 'UPCOM') - industry_icb: str, ICB industry classification code - foreign_buy_vol, foreign_sell_vol: int, foreign investor volumes - foreign_ownership_pct: float, foreign ownership percentage """# =========================================================================# Replace with actual DataCore API call:# from datacore import Client# client = Client(api_key='YOUR_KEY')# df = client.daily_stock(# start=config['beg_date'], end=config['end_date'],# exchanges=config['exchanges']# )# =========================================================================print("Connect to DataCore.vn and load daily stock data.")print("Expected schema: ticker, date, open, high, low, close, volume,")print(" shares_outstanding, adjusted_close, adj_factor, bid, ask,")print(" exchange, industry_icb, foreign_buy_vol, foreign_sell_vol,")print(" foreign_ownership_pct")returnNone# Replace with actual datadef apply_sample_filters(df, config):"""Apply sequential sample construction filters."""print("\n=== Sample Construction ===") n0 =len(df)# Date filter df = df[(df['date'] >= config['beg_date']) & (df['date'] <= config['end_date'])].copy()print(f"[1] Date filter: {len(df):,} obs (from {n0:,})")# Exchange filter df = df[df['exchange'].isin(config['exchanges'])].copy()print(f"[2] Exchange filter ({config['exchanges']}): {len(df):,} obs")# Price filter df = df[df['close'] >= config['min_price']].copy()print(f"[3] Price >= {config['min_price']:,} VND: {len(df):,} obs")# Compute daily return from adjusted prices df = df.sort_values(['ticker', 'date']) df['ret'] = df.groupby('ticker')['adjusted_close'].pct_change()# Flag price limit hits df['limit_hit'] = ( ((df['exchange'] =='HOSE') & (df['ret'].abs() >= config['price_limit_hose'] -0.001)) | ((df['exchange'] =='HNX') & (df['ret'].abs() >= config['price_limit_hnx'] -0.001)) ) n_tickers = df['ticker'].nunique()print(f"\nFinal sample: {len(df):,} stock-day obs, "f"{n_tickers} unique tickers")print(f"Limit-hit days: {df['limit_hit'].sum():,} "f"({100*df['limit_hit'].mean():.2f}%)")return df
34.3 Điều chỉnh theo hành động doanh nghiệp
Điều chỉnh đúng đắn theo các hành động doanh nghiệp là yếu tố then chốt đối với các thước đo DIVOP dựa trên khối lượng, vì các sự kiện như chia tách cổ phiếu, phát hành cổ phiếu thưởng và phát hành quyền mua làm thay đổi số cổ phiếu đang lưu hành và có thể tạo ra các đỉnh nhọn giả tạo trong vòng quay đo được. Chúng ta cần dùng các hệ số điều chỉnh tích lũy tính đến cổ tức bằng cổ phiếu (cổ phiếu thưởng), chia tách cổ phiếu, phát hành quyền mua và cổ tức tiền mặt (chỉ điều chỉnh giá). Chúng ta dùng các hệ số này để xây dựng khối lượng điều chỉnh và số cổ phiếu đang lưu hành điều chỉnh:
Điều này bảo đảm tỷ lệ vòng quay nhất quán giữa các sự kiện hành động doanh nghiệp.
Corporate action adjustment
def adjust_for_corporate_actions(df):"""Apply cumulative adjustment factors to volume and shares outstanding.""" df = df.copy() df['adj_volume'] = df['volume'] * df['adj_factor'] df['adj_shares_out'] = df['shares_outstanding'] * df['adj_factor']# Daily turnover ratio df['turnover'] = np.where( df['adj_shares_out'] >0, df['adj_volume'] / df['adj_shares_out'], np.nan )# Flag extreme turnover (> 50% of float) extreme = df['turnover'] >0.50if extreme.any():print(f"Warning: {extreme.sum()} obs with turnover > 50%, set to NaN") df.loc[extreme, 'turnover'] = np.nanreturn df
34.4 Xây dựng lịch giao dịch
Phương pháp hồi quy trượt cho SUV và biến động đòi hỏi một lịch giao dịch bảo đảm mỗi cửa sổ ước lượng chứa chính xác số ngày giao dịch đã định. Chúng ta xây dựng lịch này trực tiếp từ các ngày giao dịch quan sát được.
Build trading calendar for rolling estimation windows
def build_trading_calendar(df, config):""" Map each trading date to its estimation window [est_start, est_end]. For date t, the estimation window runs from t - gap - est_window to t - gap - 1 (in trading-day terms). """ trading_dates =sorted(df['date'].unique()) trading_dates = pd.Series(trading_dates) est_window = config['est_window'] gap = config['gap'] offset = est_window + gap records = []for i inrange(offset, len(trading_dates)): records.append({'date': trading_dates.iloc[i],'est_start': trading_dates.iloc[i - gap - est_window],'est_end': trading_dates.iloc[i - gap -1] }) calendar = pd.DataFrame(records)print(f"Trading calendar: {len(calendar)} dates, "f"{calendar['date'].min()} to {calendar['date'].max()}")return calendar
35 Các biến đại diện DIVOP dựa trên khối lượng
35.1 Động cơ lý thuyết
Khối lượng giao dịch từ lâu đã được công nhận là biến đại diện tự nhiên cho sự phân kỳ quan điểm của nhà đầu tư. Trong khung kỳ vọng hợp lý của Milgrom và Stokey (1982), giao dịch chỉ xảy ra khi các nhà đầu tư bất đồng về giá trị của một chứng khoán (tức là một “định lý không giao dịch” hàm ý, theo phản đảo, rằng khối lượng giao dịch quan sát được phải phản ánh một dạng niềm tin không đồng nhất nào đó). Harris và Raviv (1993) và Kandel và Pearson (1995) hình thức hóa trực giác này, cho thấy khối lượng giao dịch có quan hệ cùng chiều với mức phân tán của niềm tin ban đầu của nhà đầu tư và với mức độ thông tin công khai được diễn giải khác nhau.
Khó khăn khi dùng khối lượng giao dịch thô làm biến đại diện DIVOP là khối lượng còn chịu tác động của các yếu tố không liên quan đến bất đồng, bao gồm tái cân bằng danh mục, yêu cầu về thanh khoản, bán để ghi nhận lỗ thuế và các hiệu ứng tái cơ cấu chỉ số. Garfinkel (2009) đề xuất hai cách để tách thành phần bất đồng khỏi khối lượng thô. Cách thứ nhất, Khối lượng không được giải thích (DTO), loại bỏ các hiệu ứng khối lượng toàn thị trường và xu hướng dài hạn. Cách thứ hai, Khối lượng không được giải thích đã chuẩn hóa (SUV), kiểm soát thêm hàm lượng thông tin của lợi nhuận thông qua một hồi quy mặt cắt ngang, tách riêng thành phần “bất đồng thuần túy” của hoạt động giao dịch.
35.2 Khối lượng không được giải thích (DTO)
35.2.1 Phương pháp xây dựng
Việc xây dựng thước đo Khối lượng không được giải thích gồm bốn bước.
Bước 1: Tính vòng quay hằng ngày cấp doanh nghiệp. Với mỗi cổ phiếu \(i\) vào ngày \(t\):
Khác với phương pháp ở Hoa Kỳ vốn tính vòng quay thị trường chỉ trên các cổ phiếu NYSE/AMEX và áp dụng một điều chỉnh tỷ lệ cho các chứng khoán NASDAQ (theo A.-M. Anderson và Dyl 2005), chúng ta tính vòng quay thị trường trên mọi cổ phiếu phổ thông của HOSE và HNX mà không có bất kỳ việc điều chỉnh tỷ lệ khối lượng riêng cho từng sàn nào. Cả hai sàn của Việt Nam đều vận hành như thị trường dẫn dắt bởi lệnh (HOSE dùng khớp lệnh liên tục; HNX dùng kết hợp khớp lệnh liên tục và đấu giá định kỳ) mà không có vấn đề tính trùng của thị trường nhà tạo lập (dealer market), vấn đề vốn đòi hỏi điều chỉnh khối lượng NASDAQ trong các nghiên cứu ở Hoa Kỳ.
Bước 3: Tính vòng quay đã điều chỉnh theo thị trường.
trong đó \(\text{Median}_{180}(\text{MATO}_{i,t-7})\) là trung vị của vòng quay đã điều chỉnh theo thị trường trong cửa sổ 180 ngày giao dịch kết thúc 7 ngày trước ngày \(t\). Độ trễ 7 ngày ngăn vòng quay của ngày hiện tại ảnh hưởng đến mức cơ sở dùng để loại bỏ xu hướng của chính nó.
Một số đặc điểm của thị trường Việt Nam cần được chú ý khi xây dựng DTO:
Không cần điều chỉnh khối lượng kiểu NASDAQ. Cả HOSE và HNX đều là thị trường đấu giá dẫn dắt bởi lệnh. Điều chỉnh tính trùng áp dụng cho các chứng khoán NASDAQ trong các nghiên cứu ở Hoa Kỳ là không cần thiết.
Cổ phiếu giao dịch thưa thớt. Một tỷ lệ đáng kể cổ phiếu niêm yết của Việt Nam, đặc biệt trên HNX, có thể có khối lượng bằng không trong nhiều ngày giao dịch. Với các cổ phiếu giao dịch không liên tục, trung vị trượt có thể bị chệch về không, khiến DTO kém thông tin hơn. Chúng ta yêu cầu ít nhất 80% số ngày có khối lượng khác không trong mỗi cửa sổ ước lượng.
Tác động của biên độ giá lên khối lượng. Khi một cổ phiếu chạm biên độ giá hằng ngày, các lệnh chưa khớp tích tụ và khối lượng ghi nhận có thể thấp hơn khối lượng khớp thực. Ngày hôm sau thường xuất hiện hiệu ứng “bắt kịp”. Các nhà nghiên cứu nên cân nhắc đánh dấu các ngày chạm biên độ.
Phân rã giao dịch của nhà đầu tư nước ngoài. DataCore cung cấp khối lượng theo loại nhà đầu tư (nước ngoài so với trong nước). Các nhà nghiên cứu có thể muốn xây dựng các thước đo DTO riêng cho khối lượng của nhà đầu tư nước ngoài và trong nước, hoặc dùng tỷ lệ khối lượng nước ngoài trên trong nước như một chiều bổ sung của sự bất đồng.
35.3 Khối lượng không được giải thích đã chuẩn hóa (SUV)
35.3.1 Phương pháp xây dựng
Thước đo Khối lượng không được giải thích đã chuẩn hóa, do Garfinkel (2009) đề xuất, tách riêng thành phần bất đồng của khối lượng bằng cách kiểm soát một cách tường minh hàm lượng thông tin của lợi nhuận. Ý tưởng là khối lượng giao dịch có cả thành phần thanh khoản lẫn thành phần thông tin tương quan với độ lớn và dấu của lợi nhuận. Bằng cách hồi quy vòng quay theo lợi nhuận có dấu và lấy phần dư chuẩn hóa, SUV nắm bắt khối lượng do bất đồng gây ra sau khi kiểm soát cả xu hướng thanh khoản lẫn giao dịch dựa trên thông tin.
Với mỗi cổ phiếu \(i\), tại mỗi ngày giao dịch \(t\), chúng ta ước lượng bằng dữ liệu từ cửa sổ ước lượng \([\tau_1, \tau_2]\):
trong đó \(\hat{\text{Turn}}_{i,t}\) là vòng quay dự báo và \(\hat{\sigma}_{\epsilon,i}\) là RMSE từ Phương trình 35.1.
Đặc tả bất đối xứng với các hệ số riêng cho lợi nhuận dương và âm phản ánh việc quan hệ khối lượng-lợi nhuận khác nhau theo dấu của lợi nhuận. Ở Hoa Kỳ, áp lực mua có xu hướng tạo ra khối lượng lớn hơn áp lực bán do các ma sát bán khống. Ở Việt Nam, nơi bán khống không khả dụng cho đến năm 2025, sự bất đối xứng này được kỳ vọng còn rõ rệt hơn vì mọi hoạt động bán đều bị giới hạn ở các cổ đông hiện hữu.
Construct Standardized Unexplained Volume (SUV)
def compute_suv(df, calendar, config):""" Compute Standardized Unexplained Volume via rolling regressions. For each stock-date, regress Turn on RetPos and RetNeg over the estimation window, then compute SUV = (actual - predicted) / RMSE. """ est_window = config['est_window'] min_obs =int(est_window * config['min_volume_days'])# Prepare signed return components df = df.copy() df['ret_pos'] = np.where(df['ret'] >0, np.abs(df['ret']), 0.0) df['ret_neg'] = np.where( (df['ret'] <0) & df['ret'].notna(), np.abs(df['ret']), 0.0 ) results = [] grouped = {t: g for t, g in df.groupby('ticker')}for _, cal_row in calendar.iterrows(): dt = cal_row['date'] est_s, est_e = cal_row['est_start'], cal_row['est_end']for ticker, tdata in grouped.items():# Estimation window est = tdata[ (tdata['date'] >= est_s) & (tdata['date'] <= est_e) ].dropna(subset=['turnover', 'ret_pos', 'ret_neg'])iflen(est) < min_obs:continue# Event date evt = tdata[tdata['date'] == dt]if evt.empty or evt['turnover'].isna().all():continue# OLS: Turn = alpha + beta_pos * RetPos + beta_neg * RetNeg X = est[['ret_pos', 'ret_neg']].values y = est['turnover'].values reg = LinearRegression().fit(X, y) y_hat = reg.predict(X) rmse = np.sqrt(np.mean((y - y_hat) **2))if rmse <=0:continue# Predict and standardize for event date X_evt = evt[['ret_pos', 'ret_neg']].values pred = reg.predict(X_evt)[0] actual = evt['turnover'].values[0] suv = (actual - pred) / rmse results.append({'ticker': ticker, 'date': dt,'suv': suv,'predicted_turnover': pred,'rmse_turn': rmse,'n_est': len(est),'alpha_turn': reg.intercept_,'beta_pos': reg.coef_[0],'beta_neg': reg.coef_[1], }) suv_df = pd.DataFrame(results)print(f"SUV: {len(suv_df):,} stock-date obs")print(f" Mean: {suv_df['suv'].mean():.4f}, "f"Median: {suv_df['suv'].median():.4f}")return suv_df
35.3.2 Diễn giải các hệ số hồi quy SUV
Các hệ số ước lượng từ Phương trình 35.1 cung cấp thông tin về vi cấu trúc thị trường. Garfinkel (2009) báo cáo \(\hat{\beta}^{+} > \hat{\beta}^{-}\) đối với hầu hết cổ phiếu Hoa Kỳ. Ở Việt Nam, chúng ta kỳ vọng sự bất đối xứng này còn mạnh hơn vì:
Không có bán khống (trước 2025): Mọi lệnh bán đều do cổ đông hiện hữu thực hiện, làm hạn chế phản ứng của khối lượng đối với lợi nhuận âm.
Thanh toán T+2: Nhà đầu tư không thể tái đầu tư ngay tiền bán, làm giảm thêm khối lượng bên bán.
Biên độ giá: Biên độ hằng ngày \(\pm\) 7% (HOSE) và \(\pm\) 10% (HNX) cắt cụt phân phối lợi nhuận, nén khoảng biến thiên của cả hai biến hồi quy.
Các nhà nghiên cứu nên báo cáo thống kê mô tả của \((\hat{\alpha}, \hat{\beta}^{+}, \hat{\beta}^{-}, R^2)\) theo mặt cắt ngang và theo thời gian.
Diagnostic statistics for SUV turnover regressions
def suv_diagnostics(suv_df):"""Report cross-sectional summary of SUV regression parameters."""print("\n=== SUV Regression Diagnostics ===") params = ['alpha_turn', 'beta_pos', 'beta_neg']print(suv_df[params].describe( percentiles=[.05, .25, .50, .75, .95] ).T.to_string(float_format='{:.6f}'.format))# Asymmetry test diff = suv_df['beta_pos'] - suv_df['beta_neg']print(f"\nbeta_pos - beta_neg: mean = {diff.mean():.6f}, "f"frac > 0 = {(diff >0).mean():.3f}")
36 Các biến đại diện DIVOP dựa trên biến động
36.1 Biến động lợi nhuận tổng
36.1.1 Động cơ lý thuyết
Biến động lợi nhuận cổ phiếu đóng vai trò biến đại diện cho sự phân kỳ quan điểm qua nhiều kênh. Shalen (1993) xây dựng một mô hình trong đó cả khối lượng lẫn biến động đều tăng theo mức phân tán niềm tin của nhà đầu tư. Scheinkman và Xiong (2003) dự đoán rằng biến động cao hơn phản ánh thành phần giao dịch đầu cơ do các nhà đầu tư tự tin thái quá bất đồng về giá trị thúc đẩy. Về mặt thực nghiệm, Boehme, Danielsen, và Sorescu (2006) và Chatterjee, John, và Yan (2012) dùng biến động đặc thù làm biến đại diện DIVOP và thấy nó tương quan dương với các thước đo bất đồng khác và gắn với lợi nhuận về sau thấp hơn khi các hạn chế bán khống có hiệu lực ràng buộc.
36.1.2 Xây dựng
Biến động lợi nhuận tổng là độ lệch chuẩn của lợi nhuận hằng ngày trong cửa sổ ước lượng trượt:
trong đó \(N_i\) là số quan sát lợi nhuận không bị thiếu của cổ phiếu \(i\) trong cửa sổ \([\tau_1, \tau_2]\).
36.2 Biến động đặc thù (IVOL)
Biến động đặc thù tách riêng biến thiên lợi nhuận đặc thù của doanh nghiệp bằng cách loại bỏ thành phần hệ thống được giải thích bởi biến động thị trường. Chúng ta tính IVOL từ phần dư của mô hình thị trường:
Các nhà nghiên cứu có thể mở rộng sang mô hình ba nhân tố hoặc năm nhân tố của Fama và French (1993) bằng các danh mục nhân tố Việt Nam được xây dựng ở những phần khác trong cuốn sách này. Một mô hình nhân tố phong phú hơn cho các ước lượng IVOL tách biệt tốt hơn sự bất đồng thực sự mang tính đặc thù, với cái giá là phải xây dựng các danh mục nhân tố.
Construct total and idiosyncratic volatility
def compute_volatility(df, calendar, config):""" Compute total return volatility and idiosyncratic volatility via rolling estimation windows. Total vol = std(returns) in window. IVOL = std(residuals) from market model regression. """ est_window = config['est_window'] min_obs =int(est_window * config['min_volume_days'])# Value-weighted market returndef _vw_ret(g): valid = g.dropna(subset=['ret'])if valid.empty:return np.nan w = valid['adj_shares_out'] * valid['close']return np.average(valid['ret'], weights=w) mkt_ret = df.groupby('date').apply(_vw_ret).reset_index() mkt_ret.columns = ['date', 'mkt_ret'] df = df.merge(mkt_ret, on='date', how='left') results = [] grouped = {t: g for t, g in df.groupby('ticker')}for _, cal_row in calendar.iterrows(): dt = cal_row['date'] est_s, est_e = cal_row['est_start'], cal_row['est_end']for ticker, tdata in grouped.items(): est = tdata[ (tdata['date'] >= est_s) & (tdata['date'] <= est_e) ].dropna(subset=['ret', 'mkt_ret'])iflen(est) < min_obs:continue# Total volatility total_vol = est['ret'].std()# Market model -> IVOL X = est[['mkt_ret']].values y = est['ret'].values reg = LinearRegression().fit(X, y) resid = y - reg.predict(X) ivol = np.std(resid, ddof=1) results.append({'ticker': ticker, 'date': dt,'total_volatility': total_vol,'idio_volatility': ivol,'market_beta': reg.coef_[0],'market_alpha': reg.intercept_,'r_squared_mm': reg.score(X, y),'n_vol': len(est), }) vol_df = pd.DataFrame(results)print(f"Volatility: {len(vol_df):,} stock-date obs")print(f" Total vol (ann. mean): "f"{vol_df['total_volatility'].mean() * np.sqrt(252):.4f}")print(f" IVOL (ann. mean): "f"{vol_df['idio_volatility'].mean() * np.sqrt(252):.4f}")return vol_df
36.2.1 Những lưu ý riêng của Việt Nam đối với biến động
Biên độ giá làm nén biến động đo được. Biên độ hằng ngày \(\pm\) 7% (HOSE) và \(\pm\) 10% (HNX) cắt cụt phân phối lợi nhuận một cách cơ học, dẫn đến đánh giá thấp biến động thực. Vào các ngày chạm biên độ, lợi nhuận cân bằng thực có thể vượt lợi nhuận quan sát được. Các nhà nghiên cứu cần lưu ý rằng các thước đo DIVOP dựa trên biến động có thể bị chệch xuống đối với các cổ phiếu thường xuyên chạm biên độ.
Sự tập trung của VN-Index. VN-Index có mức độ tập trung cao, 10 cổ phiếu hàng đầu thường chiếm 50-60% trọng số chỉ số. Với các cổ phiếu vốn hóa nhỏ và vừa, lợi nhuận thị trường trọng số bằng nhau hoặc một chỉ số tổng hợp HOSE+HNX có thể cung cấp nhân tố thị trường tốt hơn trong Phương trình 36.2.
Giao dịch thưa thớt và lợi nhuận không đồng bộ. Với các cổ phiếu giao dịch thưa thớt, các ngày có lợi nhuận bằng không liên tiếp có thể làm giảm biến động đo được. Điều chỉnh của Dimson (1979) (đưa lợi nhuận thị trường trễ và dẫn trước vào mô hình thị trường) có thể giúp hiệu chỉnh thiên lệch giao dịch không đồng bộ trong ước lượng beta, dù tác động của nó lên IVOL thường nhỏ.
37 Các biến đại diện DIVOP dựa trên chênh lệch giá và thanh khoản
37.1 Chênh lệch giá mua–bán (BASPREAD)
37.1.1 Động cơ lý thuyết
Chênh lệch giá mua–bán phản ánh chi phí lựa chọn bất lợi mà các bên cung cấp lệnh giới hạn phải gánh. Khi nhà đầu tư có niềm tin không đồng nhất, mỗi giao dịch có nhiều khả năng truyền tải thông tin riêng hơn, làm tăng thành phần lựa chọn bất lợi của chênh lệch giá. Handa, Schwartz, và Tiwari (2003) chỉ ra rằng trong các thị trường dẫn dắt bởi lệnh, chênh lệch giá nới rộng khi sự phân kỳ quan điểm tăng vì các bên cung cấp lệnh giới hạn đối mặt rủi ro lớn hơn là bị các nhà giao dịch có thông tin khai thác. Chung và Zhang (2014) chứng minh rằng chênh lệch giá mua–bán đóng cửa từ dữ liệu hằng ngày cung cấp xấp xỉ đáng tin cậy cho chênh lệch hiệu dụng trong ngày.
37.1.2 Xây dựng
Chúng ta tính chênh lệch giá mua–bán theo tỷ lệ bằng dữ liệu báo giá cuối ngày:
trong đó \(\text{Midpoint}_{i,t} = (\text{Ask}_{i,t} + \text{Bid}_{i,t}) / 2\). Khi không có giá mua và giá bán cuối ngày, chúng ta dùng biên độ cao–thấp trong ngày làm phương án dự phòng. Theo Chung và Zhang (2014), chúng ta xóa các quan sát mà cả Bid và Ask đều bằng không, và những quan sát mà chênh lệch giá vượt quá 50% điểm giữa.
37.2 Phi thanh khoản Amihud (ILLIQ)
Tỷ số Amihud (2002) đo lường tác động giá của dòng lệnh:
trong đó \(\text{DolVol}_{i,t} = \text{Volume}_{i,t} \times \text{Price}_{i,t}\) (tính bằng tỷ VND để thu nhỏ thang đo). ILLIQ cao hơn phản ánh bất cân xứng thông tin lớn hơn. Chúng ta lấy trung bình các tỷ số hằng ngày theo từng tháng và dùng phép biến đổi logarit vì phân phối lệch phải nặng.
37.2.1 Những lưu ý riêng của Việt Nam đối với chênh lệch giá và thanh khoản
Biểu bước giá. Việt Nam dùng bước giá thay đổi: 10 VND (giá < 10,000), 50 VND (10,000–49,950) và 100 VND (≥ 50,000) trên HOSE. Các mức này đặt ra một sàn dưới cho chênh lệch giá chào của các cổ phiếu giá thấp. Các nhà nghiên cứu cần thận trọng khi diễn giải sự biến thiên của chênh lệch giá giữa các thập phân vị giá như phản ánh sự phân kỳ quan điểm thay vì cơ chế bước giá.
Cấu trúc thị trường dẫn dắt bởi lệnh. Cả HOSE và HNX đều là các thị trường thuần dẫn dắt bởi lệnh, nơi các lệnh giới hạn công khai cung cấp thanh khoản. Điều này khiến phép xấp xỉ chênh lệch giá dựa trên CRSP của Chung và Zhang (2014) là phù hợp.
Yêu cầu về lô giao dịch. HOSE yêu cầu lô chuẩn 100 cổ phiếu cho giao dịch liên tục. Với các cổ phiếu giá cao, lô chuẩn đại diện cho một cam kết vốn lớn, có thể làm phồng chênh lệch giá chào so với chi phí giao dịch hiệu dụng.
Hiệu ứng đấu giá định kỳ. Các phiên mở cửa và đóng cửa trên HOSE dùng đấu giá định kỳ, có thể tạo ra các báo giá mua–bán khác biệt đáng kể so với chênh lệch giá trong giao dịch liên tục.
37.3 Phi thanh khoản thực hiện: ILLIQ ít nhiễu hơn
Biến đại diện ILLIQ trong Phương trình 37.2 tóm gọn cả một ngày biến động giá bằng một giá trị lợi nhuận tuyệt đối duy nhất. Lacava, Ranaldo, và Santucci de Magistris (2026) thay tử số đó bằng một ước lượng tần suất cao của chính biến thiên giá trong ngày, cho ra Amihud thực hiện
với \(r_{i,t,j}\) là lợi nhuận trong ngày trên \(M\) khoảng lấy mẫu và \(\sqrt{2/\pi}\) được chọn để Phương trình 37.3 nằm trên cùng thang đo với Phương trình 37.2. Với 45 khoảng năm phút của HOSE, sai số đo lường tương đối của tử số giảm từ khoảng 76% xuống khoảng 11%. Phần suy dẫn và các giả định của hàm ước lượng này nằm trong Mục 14.4; phần triển khai trên HOSE nằm trong Mục 4.5.6.
Lợi ích hiển nhiên là lợi ích chung của mọi biến đại diện DIVOP được dùng ở vế phải: một biến hồi quy sạch hơn gây thiên lệch suy giảm (attenuation) ít hơn, nên các hệ số dốc Fama-MacBeth trong Chương 42 được ước lượng gần giá trị thực hơn. Lập luận đó mang tính tổng quát và đã được nêu trong Mục 14.4.
Lý do chương này cần một phần xử lý riêng là một vấn đề khác và cụ thể hơn, và nó ảnh hưởng đến những kết quả mà chương này thực sự báo cáo.
37.3.1 Nhiễu lấy mẫu chung làm nhiễm bẩn ma trận tương quan
Hãy xem các biến đại diện trong chương này được xây dựng từ đâu. ILLIQ lấy \(|r_{i,t}|\) từ chuỗi lợi nhuận hằng ngày. TOTVOL lấy độ lệch chuẩn của chính chuỗi đó. IVOL lấy độ lệch chuẩn của phần dư của nó. Khi thiếu báo giá cuối ngày, BASPREAD dùng biên độ cao–thấp trong ngày làm phương án dự phòng, lấy từ cùng các bản ghi giá hằng ngày.
Đây không phải là các phép đo độc lập. Một tháng mà lợi nhuận hằng ngày của doanh nghiệp tình cờ nhận những giá trị lớn sẽ cho ILLIQ đo được cao và TOTVOL đo được cao và IVOL đo được cao, không phải vì sự phân kỳ quan điểm thực của doanh nghiệp cao, mà vì cùng một mẫu hữu hạn các lợi nhuận hằng ngày là đầu vào của cả ba. Sai số lấy mẫu là chung giữa các biến đại diện, nên nó không triệt tiêu khi chúng được đặt tương quan với nhau hoặc được kết hợp.
Điều này tác động trực tiếp đến hai việc mà chương làm. Chương 39 báo cáo các tương quan Spearman giữa các biến đại diện DIVOP và diễn giải mô thức đó như bằng chứng về việc các biến đại diện nắm bắt những chiều nào của sự phân kỳ. Chương 40 xây dựng một chỉ số tổng hợp bằng cách trích thành phần chính thứ nhất. Cả hai đều được tính trên cấu trúc tương quan của các biến đại diện đo được, và do đó đều hấp thụ bất kỳ tương quan nào mà các lợi nhuận hằng ngày dùng chung tạo ra.
Mô phỏng dưới đây tách riêng hiệu ứng này. Biến động thực và khối lượng giao dịch thực được rút độc lập giữa các doanh nghiệp, nên mọi tương quan vượt mức đều có thể quy cho cách xây dựng chứ không phải yếu tố kinh tế. Biến đối chứng then chốt là cột TOTVOL (disjoint), tính biến động từ lợi nhuận của một tháng khác của cùng doanh nghiệp: nó đo cùng biến động tiềm ẩn nhưng không chia sẻ nhiễu lấy mẫu với ILLIQ, nên khoảng cách giữa nó và tương quan cùng cửa sổ thông thường chính là thành phần cơ học.
Shared sampling noise between ILLIQ and the volatility proxies
rng_ri = np.random.default_rng(2026)N_SIM, D_MONTH, M_HF =8000, 21, 45K_HF = np.sqrt(2/ np.pi)def simulate_month(vol_dispersion):""" One cross-section of firm-months. True volatility and true dollar volume are INDEPENDENT by construction, so any measured association between illiquidity and volatility beyond sqrt(sigma)/DolVol is an artefact. `vol_dispersion` is the cross-sectional sd of log dollar volume: wide for the full market, narrow within a size decile. """ sigma = np.exp(rng_ri.normal(np.log(0.022), 0.35, N_SIM)) dvol = np.exp(rng_ri.normal(np.log(5.0), vol_dispersion, N_SIM)) beta = rng_ri.normal(1.0, 0.3, N_SIM) mkt = rng_ri.normal(0, 0.012, (1, D_MONTH)) R = beta[:, None] * mkt + rng_ri.normal(0, 1, (N_SIM, D_MONTH)) * sigma[:, None] RV = (sigma[:, None] **2) * rng_ri.chisquare(M_HF, (N_SIM, D_MONTH)) / M_HF# Same firm, same true sigma, DIFFERENT month: no shared sampling noise. R_alt = beta[:, None] * mkt + rng_ri.normal(0, 1, (N_SIM, D_MONTH)) * sigma[:, None]returndict( sigma=sigma, illiq_true=K_HF * sigma / dvol, illiq_classic=np.abs(R).mean(1) / dvol, illiq_realized=K_HF * np.sqrt(RV).mean(1) / dvol, totvol=R.std(1, ddof=1), totvol_disjoint=R_alt.std(1, ddof=1), ivol=(R - beta[:, None] * mkt).std(1, ddof=1), )def rho(a, b):return scipy_stats.spearmanr(a, b).statisticrows_ri = []for label, disp in [("full cross-section", 0.90), ("within size decile", 0.30), ("volume near-constant", 0.10)]: s = simulate_month(disp) rows_ri.append({"volume dispersion": label,"TRUE illiq vs TRUE vol": round(rho(s["illiq_true"], s["sigma"]), 3),"classic vs TOTVOL": round(rho(s["illiq_classic"], s["totvol"]), 3),"classic vs TOTVOL (disjoint)": round(rho(s["illiq_classic"], s["totvol_disjoint"]), 3),"realized vs TOTVOL": round(rho(s["illiq_realized"], s["totvol"]), 3),"fidelity: classic": round(rho(s["illiq_classic"], s["illiq_true"]), 3),"fidelity: realized": round(rho(s["illiq_realized"], s["illiq_true"]), 3), })print("Spearman correlations; true volatility and true volume are INDEPENDENT")print(pd.DataFrame(rows_ri).set_index("volume dispersion").T.to_string())def normal_scores(x):"""Rank-based normal scores, matching the chapter's rank-correlation approach."""return scipy_stats.norm.ppf(scipy_stats.rankdata(x) / (len(x) +1))s = simulate_month(0.30)print("\nPCA composite of (ILLIQ, TOTVOL, IVOL), within size decile:")for name, ill in [("classic ILLIQ", s["illiq_classic"]), ("realized ILLIQ", s["illiq_realized"]), ("TRUE illiquidity", s["illiq_true"])]: X = np.column_stack([normal_scores(c) for c in (ill, s["totvol"], s["ivol"])]) C = np.corrcoef(X, rowvar=False) ev = np.linalg.eigvalsh(C)[::-1]print(f" {name:<17} PC1 share={ev[0] / ev.sum():.3f} "f"corr(ILLIQ,TOTVOL)={C[0, 1]:.3f} corr(ILLIQ,IVOL)={C[0, 2]:.3f}")
Spearman correlations; true volatility and true volume are INDEPENDENT
volume dispersion full cross-section within size decile volume near-constant
TRUE illiq vs TRUE vol 0.353 0.739 0.958
classic vs TOTVOL 0.315 0.690 0.932
classic vs TOTVOL (disjoint) 0.239 0.514 0.726
realized vs TOTVOL 0.295 0.609 0.824
fidelity: classic 0.977 0.895 0.862
fidelity: realized 1.000 0.999 0.998
PCA composite of (ILLIQ, TOTVOL, IVOL), within size decile:
classic ILLIQ PC1 share=0.841 corr(ILLIQ,TOTVOL)=0.713 corr(ILLIQ,IVOL)=0.655
realized ILLIQ PC1 share=0.829 corr(ILLIQ,TOTVOL)=0.628 corr(ILLIQ,IVOL)=0.685
TRUE illiquidity PC1 share=0.829 corr(ILLIQ,TOTVOL)=0.629 corr(ILLIQ,IVOL)=0.686
Bốn phát hiện, mỗi phát hiện có tác động trực tiếp đến cách đọc các kết quả trong Chương 39 và Chương 40.
Mức thổi phồng cơ học là lớn, và lớn nhất đúng ở nơi chương này làm việc. Trong một thập phân vị quy mô, tương quan đo được giữa ILLIQ cổ điển và TOTVOL là 0.690 khi cả hai được tính từ lợi nhuận của cùng một tháng, nhưng chỉ là 0.514 khi TOTVOL đến từ một cửa sổ tách rời. Khoảng một phần tư mối liên hệ biểu kiến là do nhiễu lấy mẫu chung tạo ra. Trong trường hợp khối lượng gần như không đổi, khoảng cách còn nới rộng hơn, từ 0.726 lên 0.932. Vì nghiên cứu DIVOP thường xuyên kiểm soát theo quy mô, và quy mô là yếu tố chi phối chính của độ phân tán của giá trị giao dịch, nên chế độ liên quan là chế độ phân tán hẹp, không phải toàn bộ mặt cắt ngang.
Thước đo thực hiện loại bỏ gần như toàn bộ. Độ trung thực của nó đối với phi thanh khoản thực là 0.999 so với 0.895 của thước đo cổ điển trong một thập phân vị quy mô, và tương quan của nó với TOTVOL (0.609) phản ánh quan hệ thực bị suy giảm chỉ bởi sai số lấy mẫu của chính TOTVOL, không phải bởi bất kỳ thành phần chung nào.
Biến đại diện cổ điển mất lợi thế đúng ở nơi tử số phải gánh vác công việc. Độ trung thực đối với phi thanh khoản thực giảm từ 0.977 trong toàn bộ mặt cắt ngang xuống 0.862 khi khối lượng gần như không đổi, trong khi thước đo thực hiện duy trì trên 0.998 xuyên suốt. Cách diễn giải là cách đã được dự báo trong Mục 14.3.1.1: trên toàn thị trường, tỷ số cổ điển xếp hạng các cổ phiếu tốt vì mẫu số biến thiên rất lớn và được đo không có sai số. Hãy loại bỏ biến thiên đó bằng cách kiểm soát theo quy mô, và phần còn lại là tử số nhiễu.
Chỉ số tổng hợp PCA thừa hưởng sự nhiễm bẩn, dù ở mức khiêm tốn. Dùng biến đại diện cổ điển, tương quan ILLIQ-TOTVOL đi vào PCA là 0.713 so với giá trị thực 0.629, và tỷ lệ phương sai của thành phần thứ nhất là 0.841 so với giá trị thực 0.829. Thay bằng thước đo thực hiện thì tái tạo gần như chính xác ma trận tương quan thực và tỷ lệ PC1 thực (0.628 và 0.829). Do đó chỉ số tổng hợp bị phóng đại nhẹ khi dùng làm bản tóm tắt biến thiên chung: nó một phần đang tóm tắt sai số đo lường chung thay vì một nhân tố phân kỳ quan điểm chung. Sự méo mó ở đây nhỏ vì chỉ một trong ba đầu vào được thay thế; một chỉ số tổng hợp được xây hoàn toàn từ các thống kê hằng ngày cùng cửa sổ sẽ tệ hơn.
37.3.2 Điều này có ý nghĩa gì đối với các kết quả của chương
Các cách đọc thực tiễn là hẹp và đáng được nêu chính xác, vì các hiệu ứng trên là có thật nhưng không quá lớn.
Các tương quan được báo cáo giữa các biến đại diện dựa trên lợi nhuận là cận trên. Ở bất cứ nơi nào Chương 39 cho thấy ILLIQ tương quan với TOTVOL, IVOL hoặc BASPREAD kiểu cao–thấp, một phần của tương quan đó là do cách xây dựng chứ không phải kinh tế. Các tương quan với biến đại diện được xây từ dữ liệu khác (DTO và SUV từ vòng quay, DISP từ dự báo của nhà phân tích) không bị ảnh hưởng bởi kênh này và có thể được hiểu theo đúng giá trị báo cáo.
Một kiểm tra độ vững rẻ tiền không cần dữ liệu trong ngày nào. Tính lại ma trận tương quan với các biến đại diện biến động được ước lượng trên một cửa sổ liền kề, không chồng lấn sẽ phá vỡ trực tiếp kênh nhiễu chung. Bất kỳ tương quan nào còn tồn tại không phải là sản phẩm phụ của sai số lấy mẫu chung. Đây là cột disjoint của mô phỏng, được triển khai trên dữ liệu thực, và chỉ tốn thêm một lệnh shift.
Đừng diễn giải quá mức tỷ lệ phương sai của PC1. Nó bị chệch lên do nhiễu chung, nên nhận định rằng một nhân tố duy nhất giải thích phần lớn biến thiên chung của các biến đại diện DIVOP có phần yếu hơn so với những gì các trị riêng thô gợi ý.
Kiểm soát theo quy mô làm vấn đề trở nên hệ trọng hơn. Bất kỳ đặc tả nào hoạt động trong các nhóm quy mô đều loại bỏ biến thiên khối lượng vốn mang phần lớn tín hiệu mặt cắt ngang của ILLIQ cổ điển, để lại một biến đại diện có độ trung thực đối với phi thanh khoản thực giảm xuống còn khoảng 0.86. Đây là nơi việc thay bằng Phương trình 37.3 mang lại nhiều nhất.
37.3.3 Xây dựng
Biến đại diện thực hiện là một thay thế trực tiếp cho amihud_daily trong compute_spread_and_illiq(). Nó đòi hỏi các đầu vào trong ngày có tính đến phiên giao dịch được mô tả trong Mục 4.5.6.
Construct realized ILLIQ as a DIVOP proxy
def compute_realized_illiq(realized_daily, config, min_active=20):""" Monthly realized Amihud from a symbol-day intraday panel with columns [ticker, date, rv, bv, n_active, dvol_continuous]. `min_active` screens out days whose five-minute grid is mostly stale prices; below roughly 20 active intervals of 45 the estimator's precision advantage largely disappears (see the microstructure chapter). """ k = np.sqrt(2/ np.pi) df = realized_daily.copy() n_before =len(df) df = df[(df["n_active"] >= min_active) & (df["dvol_continuous"] >0)]print(f"Thin-trading screen: kept {len(df):,} of {n_before:,} symbol-days "f"({100*len(df) /max(n_before, 1):.1f}%)") dvol_bn = df["dvol_continuous"] /1e9 df["rilliq_daily"] = k * np.sqrt(df["rv"]) / dvol_bn df["rilliq_bv_daily"] = k * np.sqrt(df["bv"].clip(lower=0)) / dvol_bn df["ym"] = df["date"].dt.to_period("M") agg = (df.groupby(["ticker", "ym"]) .agg(rilliq_mean=("rilliq_daily", "mean"), rilliq_bv_mean=("rilliq_bv_daily", "mean"), n_days=("rilliq_daily", "size")) .reset_index()) agg = agg[agg["n_days"] >= config.get("min_days_per_month", 15)].copy() agg["log_rilliq"] = np.log(agg["rilliq_mean"] +1e-10)return aggdef totvol_disjoint(monthly_vol):""" Robustness control requiring no intraday data: pair each month's ILLIQ with the PREVIOUS month's volatility, so the two share no daily returns. """ out = monthly_vol.sort_values(["ticker", "ym"]).copy() out["totvol_lag"] = out.groupby("ticker")["totvol"].shift(1)return out
37.3.4 Những lưu ý riêng của Việt Nam
Độ phủ là ràng buộc then chốt. Dữ liệu trong ngày thực tế chỉ có cho phần thanh khoản cao của HOSE, khoảng VN30 và các doanh nghiệp vốn hóa vừa có quy mô lớn hơn. Vì bước sàng lọc loại các doanh nghiệp một cách không ngẫu nhiên đúng theo chiều đang nghiên cứu, một phân tích DIVOP giới hạn ở mẫu còn lại sẽ bị điều kiện hóa theo thanh khoản. Hãy báo cáo tỷ lệ được giữ lại.
Dùng biến thể bipower. Biên độ giá hằng ngày của Việt Nam khiến các biến động rời rạc lớn trở nên thường lệ, và một cú nhảy thông tin làm phồng phương sai thực hiện trong khi để biến thiên bipower gần như không chệch (Mục 14.4). Với một chương về sự phân kỳ quan điểm, điều này quan trọng hơn thường lệ, vì những ngày có nhiều bất đồng nhất cũng là những ngày dễ chạm biên độ nhất.
Kiểm tra cửa sổ tách rời nên được chạy trong mọi trường hợp. Nó không đòi hỏi dữ liệu nào mà chương này chưa có, nó xử lý trực tiếp sự nhiễm bẩn đã nêu ở trên, và nó áp dụng cho toàn bộ mẫu chứ không chỉ tập con thanh khoản cao.
Mẫu số không đổi.Phương trình 37.3 chỉ cải thiện tử số; các phức tạp về giao dịch thỏa thuận và báo cáo ảnh hưởng đến DolVol, được thảo luận trong chương vi cấu trúc thị trường, áp dụng như nhau cho cả hai phiên bản.
38 Phân tán dự báo của nhà phân tích
38.1 Động cơ lý thuyết
Phân tán dự báo của nhà phân tích, tức độ lệch chuẩn mặt cắt ngang của các dự báo lợi nhuận của từng nhà phân tích, là thước đo trực tiếp nhất của sự phân kỳ quan điểm. Khác với các biến đại diện dựa trên thị trường nắm bắt sự bất đồng một cách gián tiếp, phân tán dự báo đo trực tiếp sự bất đồng giữa các thành viên thị trường có thông tin. Abarbanell, Lanen, và Verrecchia (1995) thiết lập cơ sở lý thuyết, và Diether, Malloy, và Scherbina (2002) chứng minh rằng các cổ phiếu có phân tán dự báo của nhà phân tích cao hơn có lợi nhuận về sau thấp hơn, phù hợp với giả thuyết định giá quá cao của Miller.
38.2 Thách thức dữ liệu ở Việt Nam
Việc xây dựng phân tán dự báo của nhà phân tích ở Việt Nam đặt ra những thách thức đáng kể so với Hoa Kỳ:
Độ rộng của độ phủ. Trong khi I/B/E/S phủ hơn 4,000 doanh nghiệp Hoa Kỳ, chỉ có 100–150 doanh nghiệp Việt Nam thường được ít nhất 3 nhà phân tích theo dõi, tập trung ở các cổ phiếu thành phần VN30.
Nguồn dữ liệu. Dự báo của nhà phân tích có sẵn từ DataCore.vn, FiinPro, Bloomberg và Refinitiv. Việc chọn nguồn ảnh hưởng đến độ phủ và tính kịp thời.
Dự báo lỗi thời. Với độ phủ hạn chế, các dự báo có thể không được sửa đổi trong nhiều tháng. Theo phương pháp I/B/E/S, chúng ta duy trì hiệu lực của mỗi dự báo tối đa 105 ngày.
38.3 Phương pháp xây dựng
Quá trình xây dựng diễn ra như sau:
Làm sạch các dự báo riêng lẻ. Loại bỏ các quan sát mà ngày công bố đi trước ngày rà soát. Chỉ giữ lại các dự báo EPS hằng năm. Với mỗi cặp nhà phân tích-mã cổ phiếu-kỳ tài chính, chỉ giữ lại dự báo mới nhất trong mỗi tháng dương lịch.
Xử lý các ước lượng bị ngừng và bị loại. Loại bỏ các dự báo mà nhà phân tích đã rời công ty môi giới hoặc ước lượng đã bị loại khỏi đồng thuận.
Duy trì hiệu lực dự báo có kiểm soát độ lỗi thời. Mỗi dự báo có hiệu lực cho đến thời điểm sớm hơn trong số: (a) dự báo kế tiếp của cùng nhà phân tích, (b) 105 ngày sau ngày công bố, hoặc (c) ngày công bố lợi nhuận thực tế.
Mở rộng sang tần suất hằng tháng. Với mỗi cặp mã cổ phiếu-tháng, xác định mọi dự báo còn hiệu lực và tính độ phân tán.
Theo Cheong và Thomas (2011), chúng ta lưu ý rằng mỗi cách chọn chuẩn hóa tỷ lệ đều có điểm yếu. DISP1 (chuẩn hóa theo giá trị tuyệt đối của dự báo trung bình) có thể cho giá trị cực đoan khi dự báo trung bình tiến về không, điều phổ biến với các doanh nghiệp Việt Nam gần điểm hòa vốn. DISP2 (chuẩn hóa theo giá) đưa vào một tương quan âm cơ học giữa giá và độ phân tán đã chuẩn hóa. Chúng tôi khuyến nghị báo cáo cả ba phiên bản (DISP1, DISP2 và DISP_RAW không chuẩn hóa với \(\ln(\text{Price})\) làm biến kiểm soát bổ sung), và winsorize DISP1 ở phân vị thứ 1 và thứ 99.
Lưu ý về phân tán của nhà phân tích ở các thị trường có độ phủ mỏng
Với độ phủ điển hình 5–10 nhà phân tích mỗi doanh nghiệp ở Việt Nam (so với 15–25 ở Hoa Kỳ), phân tán dự báo được ước lượng với nhiễu lớn hơn đáng kể. Một thước đo phân tán từ 3 nhà phân tích có phân phối mẫu rất khác so với thước đo từ 20 nhà phân tích. Hãy luôn đưa số nhà phân tích vào làm biến kiểm soát và kiểm tra độ vững với các ngưỡng tối thiểu số nhà phân tích khác nhau (3, 5, 7).
39 Tương quan mặt cắt ngang giữa các biến đại diện DIVOP
Một câu hỏi thực nghiệm quan trọng là mức độ mà các biến đại diện DIVOP khác nhau nắm bắt cùng một cấu trúc tiềm ẩn. Nếu sự phân kỳ quan điểm là một biến tiềm ẩn được xác định rõ, chúng ta kỳ vọng có các tương quan dương giữa mọi biến đại diện, dù các tương quan không nhất thiết phải cao vì mỗi biến nắm bắt một khía cạnh khác nhau của sự bất đồng.
Spearman rank correlations among DIVOP proxies
def compute_divop_correlations(merged_df, proxies=None):""" Compute and visualize Spearman correlations among DIVOP proxies. We use rank correlations because many proxies are right-skewed. """if proxies isNone: proxies = ['dto', 'suv', 'total_volatility', 'idio_volatility','baspread', 'amihud_daily', 'disp1', 'disp2' ] available = [p for p in proxies if p in merged_df.columns] data = merged_df[available].dropna() n =len(available) rho_mat = np.eye(n) p_mat = np.zeros((n, n))for i inrange(n):for j inrange(i +1, n): rho, p = scipy_stats.spearmanr( data[available[i]], data[available[j]] ) rho_mat[i, j] = rho_mat[j, i] = rho p_mat[i, j] = p_mat[j, i] = p labels = {'dto': 'DTO', 'suv': 'SUV','total_volatility': 'VOL', 'idio_volatility': 'IVOL','baspread': 'SPREAD', 'amihud_daily': 'ILLIQ','disp1': 'DISP1', 'disp2': 'DISP2'} pretty = [labels.get(c, c) for c in available] corr_df = pd.DataFrame(rho_mat, index=pretty, columns=pretty)# Heatmap fig, ax = plt.subplots(figsize=(9, 7)) mask = np.triu(np.ones_like(corr_df, dtype=bool), k=1) sns.heatmap( corr_df, mask=mask, annot=True, fmt='.3f', cmap='RdBu_r', center=0, vmin=-0.4, vmax=0.7, square=True, linewidths=0.5, cbar_kws={'shrink': 0.8, 'label': 'Spearman ρ'}, ax=ax ) ax.set_title('Spearman Correlations Among DIVOP Proxies\n''Vietnamese Equity Market', fontsize=13, fontweight='bold') plt.tight_layout() plt.savefig('divop_correlations.png', dpi=300, bbox_inches='tight') plt.show()return corr_df
39.0.1 Các mô thức tương quan kỳ vọng
Dựa trên bằng chứng và lý thuyết ở Hoa Kỳ, chúng ta kỳ vọng:
Bảng 39.1: Cấu trúc tương quan kỳ vọng giữa các biến đại diện DIVOP
Cặp
Kỳ vọng
Cơ sở
DTO × SUV
Dương cao
Cả hai nắm bắt khối lượng bất thường; SUV tinh chỉnh DTO
VOL × IVOL
Dương cao
IVOL là tập con của biến động tổng
SPREAD × ILLIQ
Dương trung bình-cao
Cả hai nắm bắt bất cân xứng thông tin
Khối lượng × Biến động
Dương trung bình
Shalen (1993) liên kết cả hai với mức phân tán niềm tin
Nhà phân tích × Dựa trên thị trường
Dương yếu-trung bình
Các nhóm nhà đầu tư khác nhau
40 Thống kê mô tả và các tính chất mặt cắt ngang
40.1 Thống kê tóm tắt
Descriptive statistics for all DIVOP proxies
def descriptive_statistics(merged_df):"""Comprehensive descriptive statistics for DIVOP proxies.""" proxies = {'dto': 'Unexplained Volume (DTO)','suv': 'Std Unexplained Volume (SUV)','total_volatility': 'Total Return Volatility','idio_volatility': 'Idiosyncratic Volatility','baspread': 'Bid-Ask Spread','amihud_daily': 'Amihud Illiquidity','disp1': 'Analyst Disp (mean-scaled)','disp2': 'Analyst Disp (price-scaled)', } avail = {k: v for k, v in proxies.items() if k in merged_df.columns} rows = []for col, label in avail.items(): s = merged_df[col].dropna() rows.append({'Proxy': label, 'N': f'{len(s):,}','Mean': f'{s.mean():.6f}', 'Std': f'{s.std():.6f}','P5': f'{s.quantile(.05):.6f}','Median': f'{s.median():.6f}','P95': f'{s.quantile(.95):.6f}','Skew': f'{s.skew():.2f}','Kurt': f'{s.kurtosis():.2f}', }) stats = pd.DataFrame(rows).set_index('Proxy')print("\n"+"="*90)print("Descriptive Statistics of DIVOP Proxies")print("Vietnamese Equity Market, HOSE and HNX")print("="*90)print(stats.to_string())return stats
40.2 DIVOP theo đặc điểm doanh nghiệp
DIVOP by size, exchange, and foreign ownership
def divop_by_size(merged_df):"""Mean DIVOP proxies by market-cap quintile.""" df = merged_df.copy() df['mkt_cap'] = df['close'] * df['shares_outstanding'] df['size_q'] = df.groupby('date')['mkt_cap'].transform(lambda x: pd.qcut(x, 5, labels=['Q1 Small','Q2','Q3','Q4','Q5 Large'], duplicates='drop') ) proxies = ['dto','suv','total_volatility','idio_volatility','baspread','amihud_daily'] avail = [p for p in proxies if p in df.columns] tab = df.groupby('size_q')[avail].mean()print("\n=== Mean DIVOP by Size Quintile ===")print(tab.to_string(float_format='{:.6f}'.format))return tabdef divop_by_exchange(merged_df):"""Compare mean DIVOP across HOSE and HNX.""" proxies = ['dto','suv','total_volatility','idio_volatility','baspread','amihud_daily'] avail = [p for p in proxies if p in merged_df.columns] tab = merged_df.groupby('exchange')[avail].mean()print("\n=== Mean DIVOP by Exchange ===")print(tab.to_string(float_format='{:.6f}'.format))return tab
40.3 Diễn biến theo chuỗi thời gian
Time-series evolution of DIVOP proxies
def plot_divop_timeseries(merged_df):"""Plot monthly cross-sectional median DIVOP with crisis shading.""" df = merged_df.copy() df['ym'] = df['date'].dt.to_period('M') proxies = ['dto','suv','total_volatility','baspread'] avail = [p for p in proxies if p in df.columns] monthly = df.groupby('ym')[avail].median() monthly.index = monthly.index.to_timestamp() fig, axes = plt.subplots(len(avail), 1, figsize=(13, 3.5*len(avail)), sharex=True)iflen(avail) ==1: axes = [axes] labels = {'dto':'DTO','suv':'SUV','total_volatility':'Volatility','baspread':'Spread'} colors = ['#1976D2','#388E3C','#F57C00','#D32F2F']for i, (proxy, ax) inenumerate(zip(avail, axes)): ax.plot(monthly.index, monthly[proxy], color=colors[i], linewidth=1.3) ax.set_ylabel(labels.get(proxy, proxy), fontsize=10) ax.grid(True, alpha=0.25)for s, e, c in [('2008-01','2009-06','red'), ('2020-01','2020-12','orange'), ('2022-09','2023-06','purple')]: ax.axvspan(pd.Timestamp(s), pd.Timestamp(e), alpha=0.1, color=c) axes[0].set_title('Time-Series of DIVOP Proxies\n''Monthly Cross-Sectional Median, HOSE & HNX', fontsize=13, fontweight='bold')from matplotlib.patches import Patch axes[-1].legend(handles=[ Patch(facecolor='red', alpha=.2, label='GFC 2008-09'), Patch(facecolor='orange', alpha=.2, label='COVID-19'), Patch(facecolor='purple', alpha=.2, label='Bond Crisis 2022-23'), ], loc='upper right', fontsize=8) plt.tight_layout() plt.savefig('divop_timeseries.png', dpi=300, bbox_inches='tight') plt.show()
41 Tổng hợp lại
Master pipeline: build full DIVOP dataset
def build_divop_dataset(config):""" Master pipeline: load data, construct all DIVOP proxies, merge into a single stock-date panel. """ df = load_daily_data(config) df = apply_sample_filters(df, config) df = adjust_for_corporate_actions(df) calendar = build_trading_calendar(df, config) df = compute_dto(df, config) suv_df = compute_suv(df, calendar, config) vol_df = compute_volatility(df, calendar, config) df = compute_spread_and_illiq(df, config)# Merge base = df[['ticker','date','ret','close','volume','shares_outstanding','exchange','industry_icb','foreign_ownership_pct','turnover','mato','dto','baspread','amihud_daily','limit_hit']].copy()ifnot suv_df.empty: base = base.merge( suv_df[['ticker','date','suv','predicted_turnover']], on=['ticker','date'], how='left')ifnot vol_df.empty: base = base.merge( vol_df[['ticker','date','total_volatility','idio_volatility','market_beta']], on=['ticker','date'], how='left')print(f"\n=== Final DIVOP Dataset ===")print(f"Shape: {base.shape}")print(f"Tickers: {base['ticker'].nunique()}")return base
42 Các ứng dụng thực nghiệm
42.1 Ứng dụng 1: DIVOP và mặt cắt ngang của lợi nhuận
Phép kiểm định cơ bản của giả thuyết Miller là liệu các cổ phiếu có sự phân kỳ quan điểm cao hơn có lợi nhuận về sau thấp hơn hay không. Chúng ta triển khai các hồi quy mặt cắt ngang Fama-MacBeth:
trong đó \(\mathbf{X}_{i,t}\) gồm các biến kiểm soát là beta thị trường, logarit vốn hóa thị trường và logarit tỷ số giá trị sổ sách trên giá trị thị trường. Giả thuyết Miller dự đoán \(\bar{\gamma}_1 < 0\).
Fama-MacBeth regressions of returns on DIVOP
def fama_macbeth_divop(merged_df, divop_proxy='suv', controls=None, horizon=21):""" Fama-MacBeth cross-sectional regressions. Miller predicts gamma_1 < 0; Varian predicts gamma_1 > 0. """if controls isNone: controls = ['market_beta', 'log_mktcap'] df = merged_df.copy() df = df.sort_values(['ticker', 'date']) df['fwd_ret'] = df.groupby('ticker')['ret'].transform(lambda x: x.shift(-1).rolling(horizon).sum().shift(-(horizon-1)) ) df['log_mktcap'] = np.log( df['close'] * df['shares_outstanding'] +1 ) reg_vars = ['fwd_ret', divop_proxy] +\ [c for c in controls if c in df.columns] df_reg = df[['ticker','date'] + reg_vars].dropna()from numpy.linalg import lstsq results = []for date, cross in df_reg.groupby('date'):iflen(cross) <30: continue y = cross['fwd_ret'].values X_cols = [divop_proxy] + [c for c in controls if c in cross.columns] X = np.column_stack([np.ones(len(cross)), cross[X_cols].values])try: coefs, _, _, _ = lstsq(X, y, rcond=None) results.append({'date': date, 'intercept': coefs[0],f'gamma_{divop_proxy}': coefs[1], 'n': len(cross), })exceptException: continue fm = pd.DataFrame(results) gc =f'gamma_{divop_proxy}' mu = fm[gc].mean() se = fm[gc].std() / np.sqrt(len(fm)) t = mu / seprint(f"\n=== Fama-MacBeth: {divop_proxy} -> "f"{horizon}-day fwd returns ===")print(f" Mean gamma: {mu:.6f}, t-stat: {t:.3f}")if t <-1.96: print(" -> Supports Miller (1977)")elif t >1.96: print(" -> Supports Varian (1985)")else: print(" -> Inconclusive at 5%")return fm
42.2 Ứng dụng 2: DIVOP và công bố lợi nhuận
Theo Berkman và c.s. (2009), chúng ta kiểm định liệu các cổ phiếu có DIVOP cao có lợi nhuận bất thường âm quanh các đợt công bố lợi nhuận hay không, vì việc giải tỏa bất định làm giảm phần bù lạc quan.
Event study: DIVOP and earnings announcement returns
def divop_earnings_event(merged_df, ea_dates_df, divop_proxy='suv', window=(-1, 3)):""" Sort stocks into DIVOP quintiles pre-EA, compute CAR in window. Miller predicts: Q5 (high DIVOP) has lower CAR than Q1 (low DIVOP). """ df = merged_df.copy() ea = ea_dates_df.copy()# Pre-EA DIVOP value (5 days before) ea['pre_date'] = ea['ea_date'] - pd.Timedelta(days=5) ea = ea.merge( df[['ticker','date',divop_proxy]].rename( columns={'date':'pre_date'}), on=['ticker','pre_date'], how='inner' ) ea['divop_q'] = pd.qcut( ea[divop_proxy], 5, labels=['Q1 Low','Q2','Q3','Q4','Q5 High'], duplicates='drop' )print(f"\n=== EA Event Study by {divop_proxy} quintile ===")print(f" Window: ({window[0]}, {window[1]}) days")print(f" Miller predicts: Q5 has lower CAR than Q1")return ea
42.3 Ứng dụng 3: Chỉ số DIVOP tổng hợp bằng PCA
Khi cần một thước đo tóm tắt duy nhất về sự bất đồng, PCA trên bộ các biến đại diện đã chuẩn hóa sẽ trích ra “nhân tố bất đồng” chung.
Composite DIVOP index via PCA
from sklearn.preprocessing import StandardScalerfrom sklearn.decomposition import PCAdef composite_divop_pca(merged_df, proxies=None):"""Extract first principal component from standardized DIVOP proxies."""if proxies isNone: proxies = ['dto','suv','total_volatility','idio_volatility','baspread','amihud_daily'] avail = [p for p in proxies if p in merged_df.columns] data = merged_df[['ticker','date'] + avail].dropna() scaler = StandardScaler() X = scaler.fit_transform(data[avail]) pca = PCA(n_components=3) factors = pca.fit_transform(X) data['divop_composite'] = factors[:, 0]# Ensure positive correlation with inputsfor col in avail:if data['divop_composite'].corr(data[col]) <0: data['divop_composite'] *=-1break loadings = pd.DataFrame( pca.components_.T, index=avail, columns=['PC1','PC2','PC3'] )print(f"\n=== PCA Composite DIVOP ===")print(f"Variance explained: "f"{pca.explained_variance_ratio_[:3].round(3)}")print(f"\nLoadings:\n{loadings.to_string(float_format='{:.4f}'.format)}")return data[['ticker','date','divop_composite']], loadings
43 Kết luận và khuyến nghị thực tiễn
Chương này đã trình bày một phương pháp toàn diện để xây dựng bảy biến đại diện riêng biệt cho sự phân kỳ quan điểm của nhà đầu tư, được điều chỉnh cho thị trường chứng khoán Việt Nam. Chúng tôi kết thúc bằng các khuyến nghị thực tiễn:
1. Ưu tiên nhiều biến đại diện. Không có thước đo DIVOP đơn lẻ nào không có hạn chế. Chúng tôi khuyến nghị xây dựng và báo cáo kết quả cho ít nhất ba biến đại diện trải trên các kênh kinh tế khác nhau (khối lượng, biến động, chênh lệch giá hoặc dựa trên nhà phân tích).
2. Tính đến vi cấu trúc riêng của Việt Nam. Biên độ giá hằng ngày, thanh toán T+2, các ràng buộc sở hữu nước ngoài và cấu trúc thị trường dẫn dắt bởi lệnh đều ảnh hưởng đến các tính chất của DIVOP. Hãy đánh dấu các ngày chạm biên độ, đưa vào hiệu ứng cố định theo sàn, và kiểm soát sở hữu nước ngoài.
3. Việt Nam như một phòng thí nghiệm tự nhiên cho Miller (1977). Việc không có bán khống đến hết năm 2024 và sự áp đảo của nhà đầu tư cá nhân tạo ra những điều kiện khớp sát với bối cảnh lý thuyết của Miller. Việc đưa vào bán khống năm 2025 tạo ra một thử nghiệm tự nhiên để xem xét việc nới lỏng các hạn chế bán khống ảnh hưởng thế nào đến quan hệ DIVOP-lợi nhuận.
4. Kiểm soát độ phủ nhà phân tích khi dùng các thước đo DISP. Với độ phủ điển hình 5–10 nhà phân tích mỗi doanh nghiệp, phân tán dự báo được ước lượng với nhiễu lớn hơn so với các thị trường phát triển. Hãy luôn đưa số nhà phân tích vào làm biến kiểm soát và thực hiện các kiểm tra độ vững với các ngưỡng tối thiểu số nhà phân tích khác nhau.
5. Cân nhắc xây dựng chỉ số tổng hợp. Khi các nhà nghiên cứu cần một thước đo tóm tắt duy nhất về sự bất đồng, chỉ số tổng hợp dựa trên PCA được mô tả trong Chương 42 cung cấp một cách tiếp cận có nguyên tắc để tổng hợp thông tin qua các biến đại diện riêng lẻ. Thành phần chính thứ nhất thường giải thích 30-50% biến thiên chung trong bộ các thước đo DIVOP.
6. Winsorize mạnh tay. Một số biến đại diện DIVOP (đặc biệt là DISP1, ILLIQ Amihud và SUV) có các giá trị ngoại lai cực đoan trong dữ liệu Việt Nam. Winsorization ở phân vị thứ 1 và thứ 99 (hoặc thậm chí thứ 2 và thứ 98 đối với DISP1) là thiết yếu để thu được kết quả hồi quy đáng tin cậy.
7. Thận trọng với suy luận nhân quả. Các biến đại diện DIVOP là nội sinh, chúng phản ứng với cùng những đặc điểm doanh nghiệp (quy mô, đòn bẩy, tăng trưởng) vốn cũng ảnh hưởng đến lợi nhuận. Các nhà nghiên cứu nên dùng các biến kiểm soát phù hợp, cân nhắc biến công cụ khi khả thi, và nêu rõ các hạn chế của chiến lược nhận diện của mình.
Khung DIVOP đặc biệt phù hợp với thị trường Việt Nam ở giai đoạn phát triển hiện nay. Khi thị trường trưởng thành hướng tới khả năng được nâng hạng lên nhóm Thị trường mới nổi của FTSE, khi bán khống trở nên phổ biến hơn, và khi sự tham gia của nhà đầu tư tổ chức tăng lên, động lực của sự phân kỳ quan điểm và các hàm ý định giá của nó nhiều khả năng sẽ thay đổi đáng kể. Phương pháp được trình bày trong chương này trang bị cho các nhà nghiên cứu những công cụ để ghi nhận và phân tích các thay đổi đó khi chúng diễn ra.
Abarbanell, Jeffery S, William N Lanen, và Robert E Verrecchia. 1995. “Analysts’ forecasts as proxies for investor beliefs in empirical research”. Journal of Accounting and Economics 20 (1): 31–60.
Alexandridis, George, Antonios Antoniou, và Dimitris Petmezas. 2007. “Divergence of Opinion and Post-Acquisition Performance”. Journal of Business Finance & Accounting 34 (3-4): 439–60.
Amihud, Yakov. 2002. “Illiquidity and stock returns: cross-section and time-series effects”. Journal of financial markets 5 (1): 31–56. https://doi.org/10.1016/S1386-4181(01)00024-6.
Anderson, Anne-Marie, và Edward A Dyl. 2005. “Market structure and trading volume”. Journal of Financial Research 28 (1): 115–31.
Anderson, Kirsten L, Jeffrey H Harris, và Eric C So. 2007. “Opinion divergence and post-earnings announcement drift”. Available at SSRN 969736.
Berkman, Henk, Valentin Dimitrov, Prem C Jain, Paul D Koch, và Sheri Tice. 2009. “Sell on the news: Differences of opinion, short-sales constraints, and returns around earnings announcements”. Journal of Financial Economics 92 (3): 376–99.
Boehme, Rodney D, Bartley R Danielsen, và Sorin M Sorescu. 2006. “Short-sale constraints, differences of opinion, and overvaluation”. Journal of Financial and Quantitative Analysis 41 (2): 455–87.
Chatterjee, Sris, Kose John, và An Yan. 2012. “Takeovers and divergence of investor opinion”. The Review of Financial Studies 25 (1): 227–77.
Cheong, Foong Soon, và Jacob Thomas. 2011. “Why do EPS forecast error and dispersion not vary with scale? Implications for analyst and managerial behavior”. Journal of Accounting Research 49 (2): 359–401.
Chung, Kee H, và Hao Zhang. 2014. “A simple approximation of intraday spreads using daily data”. Journal of Financial Markets 17: 94–120.
Diether, Karl B, Christopher J Malloy, và Anna Scherbina. 2002. “Differences of opinion and the cross section of stock returns”. The journal of finance 57 (5): 2113–41.
Dimson, Elroy. 1979. “Risk measurement when shares are subject to infrequent trading”. Journal of financial economics 7 (2): 197–226. https://doi.org/10.1016/0304-405X(79)90013-8.
Doukas, John A, Chansog Francis Kim, và Christos Pantzalis. 2006. “Divergence of opinion and equity returns”. Journal of Financial and Quantitative Analysis 41 (3): 573–606.
Doukas, John A, Chansog Kim, và Christos Pantzalis. 2004. “Divergent opinions and the performance of value stocks”. Financial Analysts Journal 60 (6): 55–64.
Fama, Eugene F., và Kenneth R. French. 1993. “Common risk factors in the returns on stocks and bonds”. Journal of Financial Economics 33 (1): 3–56. https://doi.org/10.1016/0304-405X(93)90023-5.
Garfinkel, Jon A. 2009. “Measuring investors’ opinion divergence”. Journal of Accounting Research 47 (5): 1317–48.
Garfinkel, Jon A, và Jonathan Sokobin. 2006. “Volume, opinion divergence, and returns: A study of post–earnings announcement drift”. Journal of Accounting Research 44 (1): 85–112.
Handa, Puneet, Robert Schwartz, và Ashish Tiwari. 2003. “Quote setting and price formation in an order driven market”. Journal of financial markets 6 (4): 461–89.
Harris, Milton, và Artur Raviv. 1993. “Differences of opinion make a horse race”. The Review of Financial Studies 6 (3): 473–506.
Hong, Harrison, và Jeremy C Stein. 2003. “Differences of opinion, short-sales constraints, and market crashes”. The Review of Financial Studies 16 (2): 487–525.
Houge, Todd, Tim Loughran, Gerry Suchanek, và Xuemin Yan. 2001. “Divergence of opinion, uncertainty, and the quality of initial public offerings”. Financial management, 5–23.
Kandel, Eugene, và Neil D Pearson. 1995. “Differential interpretation of public signals and trade in speculative markets”. Journal of Political Economy 103 (4): 831–72. https://doi.org/10.1086/262005.
Milgrom, Paul, và Nancy Stokey. 1982. “Information, trade and common knowledge”. Journal of economic theory 26 (1): 17–27.
Miller, Edward M. 1977. “Risk, uncertainty, and divergence of opinion”. The Journal of finance 32 (4): 1151–68.
Nguyen, Du D, và Minh C Pham. 2018. “Search-based sentiment and stock market reactions: An empirical evidence in Vietnam”. The Journal of Asian Finance, Economics and Business 5 (4): 45–56.
Phan, Thi Nha Truc, Philippe Bertrand, Hong Hai Phan, và Xuan Vinh Vo. 2023. “The role of investor behavior in emerging stock markets: Evidence from Vietnam”. The Quarterly Review of Economics and Finance 87: 367–76.
Scheinkman, Jose A, và Wei Xiong. 2003. “Overconfidence and speculative bubbles”. Journal of political Economy 111 (6): 1183–1220.
Shalen, Catherine T. 1993. “Volume, volatility, and the dispersion of beliefs”. The Review of Financial Studies 6 (2): 405–34.
Varian, Hal R. 1985. “Divergence of opinion in complete markets: A note”. The Journal of Finance 40 (1): 309–17.
Vo, Xuan Vinh. 2015. “Foreign ownership and stock return volatility–Evidence from Vietnam”. Journal of Multinational Financial Management 30: 101–9.
———. 2017. “Do foreign investors improve stock price informativeness in emerging equity markets? Evidence from Vietnam”. Research in International Business and Finance 42: 986–91.
Vo, Xuan Vinh, và Dang Bao Anh Phan. 2017. “Further evidence on the herd behavior in Vietnam stock market”. Journal of Behavioral and Experimental Finance 13: 33–41.
# Đo lường sự phân kỳ quan điểm của nhà đầu tưMột câu hỏi nền tảng của kinh tế học tài chính là sự khác biệt về niềm tin của nhà đầu tư ảnh hưởng thế nào đến giá tài sản và hoạt động giao dịch. Trong các thị trường mà nhà đầu tư có kỳ vọng không đồng nhất về dòng tiền tương lai của doanh nghiệp, việc tổng hợp những quan điểm phân kỳ này thành một mức giá thị trường duy nhất là một bài toán không đơn giản, với những hàm ý sâu sắc đối với định giá tài sản, khả năng dự báo lợi nhuận và tính hiệu quả của thị trường. Khái niệm **sự phân kỳ quan điểm của nhà đầu tư** (sau đây viết tắt là DIVOP) đã trở thành một khái niệm trung tâm trong cả các nghiên cứu kế toán lẫn tài chính, đóng vai trò như một lăng kính để các nhà nghiên cứu xem xét môi trường thông tin của doanh nghiệp, động lực của việc giải tỏa bất định, và bản chất của phản ứng thị trường trước tin tức.Nền tảng lý thuyết của các nghiên cứu về DIVOP bắt nguồn từ @miller1977risk, người đề xuất rằng khi các nhà đầu tư bất đồng về giá trị của một chứng khoán và các hạn chế bán khống ngăn cản các nhà đầu tư bi quan thể hiện đầy đủ quan điểm của mình, thì giá thị trường sẽ phản ánh mức định giá của những nhà đầu tư lạc quan nhất. Điều này dẫn đến tình trạng định giá quá cao có hệ thống, tăng theo mức độ phân kỳ quan điểm. Tình trạng định giá quá cao kéo dài cho đến khi các sự kiện thông tin, chẳng hạn như công bố lợi nhuận, làm giảm bất đồng và giá hội tụ về giá trị cơ bản [@berkman2009sell]. @varian1985divergence đưa ra một góc nhìn khác, trong đó sự phân kỳ quan điểm là một yếu tố rủi ro bổ sung, dẫn đến lợi nhuận kỳ vọng *cao hơn* chứ không phải thấp hơn, tạo ra một sự giằng co lý thuyết đã thúc đẩy nhiều nghiên cứu thực nghiệm.Các nghiên cứu thực nghiệm về DIVOP đã mở rộng đáng kể kể từ những đóng góp nền tảng này. Các nhà nghiên cứu đã ghi nhận rằng sự phân kỳ quan điểm giúp giải thích một loạt hiện tượng bất thường trong định giá tài sản, bao gồm hiện tượng trôi dạt sau công bố lợi nhuận [@garfinkel2006volume; @anderson2007opinion], chênh lệch lợi nhuận mặt cắt ngang giữa cổ phiếu giá trị và cổ phiếu tăng trưởng [@doukas2004divergent], lợi nhuận ngắn hạn và dài hạn sau IPO [@houge2001divergence], lợi nhuận cổ phiếu trước và sau thương vụ mua lại [@alexandridis2007divergence], phần bù thâu tóm [@chatterjee2012takeovers], và mặt cắt ngang rộng của lợi nhuận cổ phiếu [@diether2002differences; @doukas2006divergence]. Sức giải thích của DIVOP đã được chứng minh bằng một tập hợp phong phú các biến đại diện thực nghiệm, từ mức phân tán dự báo của nhà phân tích và khối lượng giao dịch bất thường đến chênh lệch giá mua–bán và biến động đặc thù.Mặc dù các nghiên cứu về DIVOP đã chín muồi ở các thị trường phát triển, đặc biệt là Hoa Kỳ, việc áp dụng vào các thị trường mới nổi vẫn còn rất mỏng. Khoảng trống này đặc biệt đáng chú ý vì các điều kiện lý thuyết khiến sự phân kỳ quan điểm quan trọng nhất (cụ thể là các hạn chế bán khống có hiệu lực ràng buộc, bất cân xứng thông tin, và mức độ tinh vi không đồng đều của nhà đầu tư) có thể nói là *phổ biến hơn* ở các thị trường mới nổi so với các thị trường phát triển. Thị trường chứng khoán Việt Nam là một phòng thí nghiệm hấp dẫn để nghiên cứu sự bất đồng của nhà đầu tư. Thị trường này có một số đặc điểm làm gia tăng tính phù hợp của khung phân tích DIVOP:1. **Hạn chế bán khống có hiệu lực ràng buộc.** Bán khống không được phép ở Việt Nam cho đến tháng 1 năm 2025, và ngay cả sau khi được đưa vào, cơ chế này vẫn chỉ giới hạn ở một nhóm chứng khoán hạn chế với những ràng buộc quản lý đáng kể về việc thực hiện. Điều này phản ánh sát bối cảnh lý thuyết của @miller1977risk, nơi các nhà đầu tư bi quan không thể thể hiện đầy đủ quan điểm của mình thông qua các vị thế bán khống.2. **Sự áp đảo của nhà đầu tư cá nhân.** Nhà đầu tư cá nhân chiếm khoảng 80-85% khối lượng giao dịch hằng ngày trên HOSE và HNX, so với khoảng 25% ở Hoa Kỳ. Nhà đầu tư cá nhân dễ chịu tác động hơn của các thiên lệch hành vi, giao dịch theo tâm lý và các hạn chế trong xử lý thông tin, vốn tự nhiên làm nảy sinh niềm tin không đồng nhất [@phan2023role].3. **Bất cân xứng thông tin và thách thức về minh bạch.** Mặc dù các chuẩn mực công bố thông tin đã được cải thiện, khuôn khổ quản lý báo cáo doanh nghiệp của Việt Nam vẫn kém chặt chẽ hơn so với các thị trường phát triển. Việc công bố thông tin có chọn lọc, nộp báo cáo tài chính chậm trễ, và việc thực thi hạn chế các quy định về giao dịch nội gián tạo ra một môi trường trong đó các nhà đầu tư hoạt động với những tập thông tin khác biệt đáng kể [@vo2017further].4. **Giới hạn sở hữu nước ngoài.** Mức trần sở hữu nước ngoài (hiện là 49% đối với hầu hết các ngành, có một số ngoại lệ) tạo ra một thị trường bị phân khúc, trong đó nhà đầu tư trong nước và nước ngoài có thể có những quan điểm khác nhau một cách có hệ thống về giá trị doanh nghiệp, làm gia tăng sự phân kỳ quan điểm.5. **Độ phủ của nhà phân tích còn mỏng.** Trong khi một doanh nghiệp S&P 500 điển hình được 15-25 nhà phân tích bên bán theo dõi, độ phủ đối với cổ phiếu Việt Nam tập trung ở một số ít công ty môi giới trong nước và một vài đơn vị nghiên cứu quốc tế. Điều này làm hạn chế tính thông tin của các thước đo DIVOP truyền thống dựa trên nhà phân tích và đòi hỏi phải dựa nhiều hơn vào các biến đại diện dựa trên thị trường.Chương này trình bày một phương pháp xây dựng nhiều biến đại diện cho sự phân kỳ quan điểm của nhà đầu tư, được điều chỉnh theo các đặc điểm thể chế của thị trường Việt Nam. Chúng ta dựa trên các khung phương pháp luận do @garfinkel2009measuring và @diether2002differences thiết lập, đồng thời đưa vào những điều chỉnh phản ánh vi cấu trúc của các sàn giao dịch Việt Nam, chu kỳ thanh toán $T+2$, việc không có bán khống (cho đến gần đây), và khả năng tiếp cận dữ liệu qua các nền tảng tài chính trong nước. Cụ thể, chúng ta xây dựng và phân tích các biến đại diện DIVOP sau:- **Khối lượng không được giải thích (DTO):** Vòng quay đã điều chỉnh theo thị trường và loại bỏ xu hướng bằng trung vị trượt, nắm bắt hoạt động giao dịch bất thường do bất đồng quan điểm sau khi kiểm soát các hiệu ứng thanh khoản và hiệu ứng toàn thị trường.- **Khối lượng không được giải thích đã chuẩn hóa (SUV):** Một thước đo dựa trên hồi quy, kiểm soát một cách tường minh các thành phần thông tin và thanh khoản của khối lượng bằng cách mô hình hóa vòng quay như một hàm của lợi nhuận có dấu.- **Biến động lợi nhuận cổ phiếu (VOLATILITY):** Độ lệch chuẩn của lợi nhuận hằng ngày trong một cửa sổ ước lượng trượt, đóng vai trò biến đại diện cho mức phân tán trong định giá của nhà đầu tư.- **Chênh lệch giá mua–bán (BASPREAD):** Chênh lệch giá chào theo tỷ lệ, phản ánh thành phần lựa chọn bất lợi gắn với thông tin không đồng nhất giữa các thành viên thị trường.- **Phân tán dự báo của nhà phân tích (DISP):** Độ lệch chuẩn mặt cắt ngang của các dự báo lợi nhuận của từng nhà phân tích, đo lường trực tiếp sự bất đồng giữa các thành viên thị trường có thông tin.- **Biến động đặc thù (IVOL):** Biến động phần dư từ hồi quy mô hình nhân tố, tách riêng thành phần đặc thù của doanh nghiệp trong biến thiên lợi nhuận, phản ánh những cách diễn giải khác nhau của nhà đầu tư về thông tin cấp doanh nghiệp.- **Phi thanh khoản Amihud (ILLIQ):** Tỷ số tác động giá do @amihud2002illiquidity đề xuất, nắm bắt khía cạnh bất cân xứng thông tin của sự bất đồng thông qua phản ứng giá đối với dòng lệnh.Với mỗi biến đại diện, chúng ta mô tả động cơ lý thuyết, yêu cầu về dữ liệu, phương pháp xây dựng được điều chỉnh cho dữ liệu Việt Nam, các tính chất thực nghiệm quan sát được trong mặt cắt ngang của thị trường Việt Nam, và những lưu ý thực tiễn mà các nhà nghiên cứu cần ghi nhớ khi sử dụng các thước đo này. Chúng ta đặc biệt chú ý đến các vấn đề riêng của thị trường mới nổi, bao gồm giao dịch thưa thớt, điều chỉnh hành động doanh nghiệp, các hiệu ứng vi cấu trúc đặc thù của từng sàn, và sự tương tác giữa các ràng buộc sở hữu nước ngoài với các thước đo bất đồng của nhà đầu tư.------------------------------------------------------------------------# Khung lý thuyết {#sec-theoretical-framework}## Giả thuyết định giá quá cao của Miller (1977)Mô hình kinh điển về sự phân kỳ quan điểm và định giá tài sản bắt đầu từ @miller1977risk. Nhận định trung tâm của Miller rất đơn giản: trong một thị trường mà nhà đầu tư có niềm tin không đồng nhất về các khoản chi trả tương lai của một tài sản rủi ro và các hạn chế bán khống ngăn một số nhà đầu tư hành động theo quan điểm bi quan, giá cân bằng sẽ do nhóm nhà đầu tư lạc quan nhất về giá trị tài sản quyết định. Mức độ định giá quá cao tăng theo cả mức độ phân kỳ quan điểm lẫn độ nghiêm ngặt của các hạn chế bán khống. Về mặt hình thức, nếu nhà đầu tư $i$ gán cho một chứng khoán mức định giá $V_i$, giá thị trường $P$ thỏa mãn:$$P = E[V_i \mid V_i \geq V^*]$$trong đó $V^*$ là mức định giá của nhà đầu tư biên, vượt quá mức định giá trung bình không điều kiện $E[V_i]$ bất cứ khi nào các hạn chế bán khống có hiệu lực ràng buộc đối với một số nhà đầu tư. Mức độ định giá quá cao là:$$\text{Overpricing} = P - E[V_i] = E[V_i \mid V_i \geq V^*] - E[V_i]$$đại lượng này dương và tăng theo độ phân tán của phân phối $V_i$ (tức là sự phân kỳ quan điểm) và theo $V^*$ (tức là mức nghiêm ngặt của các hạn chế bán khống).Mô hình của Miller đưa ra một số dự đoán có thể kiểm định:- **Dự đoán theo mặt cắt ngang:** Các cổ phiếu có **mức phân kỳ quan điểm cao hơn sẽ có lợi nhuận *thấp hơn* ở các giai đoạn sau** khi giá dần điều chỉnh về giá trị cơ bản.- **Dự đoán theo chuỗi thời gian:** Các sự kiện thông tin làm giảm bất đồng (ví dụ: công bố lợi nhuận) sẽ gắn với lợi nhuận bất thường âm đối với các cổ phiếu có DIVOP cao, vì "phần bù lạc quan" tan biến.- **Dự đoán về tương tác:** Hiệu ứng định giá quá cao sẽ mạnh nhất ở các cổ phiếu đồng thời có mức phân kỳ quan điểm cao *và* chịu hạn chế bán khống có hiệu lực ràng buộc.## Các góc nhìn lý thuyết thay thế@varian1985divergence đề xuất một khung thay thế trong đó sự phân kỳ quan điểm đóng vai trò một yếu tố rủi ro. Nếu nhà đầu tư né tránh rủi ro và sự bất đồng phản ánh sự bất định thực sự về các khoản chi trả tương lai, thì **mức phân tán niềm tin cao hơn sẽ gắn với lợi nhuận kỳ vọng *cao hơn*** như một khoản bù đắp cho việc gánh thêm rủi ro. Điều này tạo ra một sự đối lập thực nghiệm rõ nét: giả thuyết Miller dự đoán mối quan hệ DIVOP-lợi nhuận mang dấu âm, trong khi mô hình Varian dự đoán mối quan hệ mang dấu dương.Sự phân biệt giữa các lý thuyết này phụ thuộc then chốt vào vi cấu trúc thị trường và bối cảnh thể chế (\@tbl-divop-theories).| Khung lý thuyết | Hạn chế bán khống | Quan hệ DIVOP-lợi nhuận | Cơ chế chính ||:-----------------|:-----------------|:-----------------|:-----------------|| @miller1977risk | Có hiệu lực ràng buộc | Âm | Thiên lệch lạc quan trong giá || @varian1985divergence | Không ràng buộc | Dương | Phần bù rủi ro cho sự bất định || @hong2003differences | Ràng buộc, thông tin lan tỏa dần | Âm, thay đổi theo thời gian | Quan điểm bi quan lan tỏa chậm || @scheinkman2003overconfidence | Ràng buộc, tự tin thái quá | Âm | Phần bù bong bóng đầu cơ |: Tóm tắt các dự đoán lý thuyết về quan hệ DIVOP-lợi nhuận dưới các giả định khác nhau {#tbl-divop-theories}@hong2003differences mở rộng khung của Miller bằng cách đưa vào sự lan tỏa thông tin dần dần. Trong mô hình của họ, thông tin tiêu cực được phản ánh vào giá chậm hơn thông tin tích cực vì các hạn chế bán khống làm tăng chi phí hành động theo quan điểm bi quan. Điều này tạo ra các mô thức giống động lượng, trong đó các cổ phiếu có DIVOP cao có lợi nhuận ngắn hạn dương (khi những người lạc quan đẩy giá lên) rồi đến lợi nhuận dài hạn âm (khi thông tin tiêu cực cuối cùng cũng đến được thị trường).@scheinkman2003overconfidence đưa thêm một chiều mới khi lưu ý rằng khi nhà đầu tư tự tin thái quá về tín hiệu riêng *và* các hạn chế bán khống có hiệu lực ràng buộc, giá cổ phiếu chứa một thành phần "bong bóng đầu cơ" phản ánh giá trị quyền chọn của việc bán lại tài sản cho một nhà đầu tư tương lai có thể còn lạc quan hơn. Mô hình này dự đoán rằng cả khối lượng giao dịch cao lẫn biến động giá cao đều gắn với tình trạng định giá quá cao, tạo cơ sở lý thuyết cho việc sử dụng các biến đại diện DIVOP dựa trên khối lượng và dựa trên biến động.## Mức độ liên quan đối với thị trường Việt NamThị trường chứng khoán Việt Nam cung cấp một bối cảnh đặc biệt sạch để kiểm định giả thuyết Miller. Thị trường chứng khoán Việt Nam vận hành mà không có bất kỳ cơ chế bán khống nào từ khi thành lập năm 2000 cho đến tháng 1 năm 2025, tức là suốt một phần tư thế kỷ, trong đó điều kiện cần đầu tiên của mô hình Miller (hạn chế bán khống có hiệu lực ràng buộc) được thỏa mãn bởi quy định chứ không phải do các ma sát thị trường. Ngay cả sau khi đưa vào bán khống có bảo đảm năm 2025, cơ chế này vẫn chỉ giới hạn ở các chứng khoán đáp ứng ngưỡng cụ thể về thanh khoản và vốn hóa thị trường, và môi trường quản lý đặt ra các yêu cầu vay mượn làm tăng đáng kể chi phí bán khống so với các thị trường phát triển.Sự áp đảo của nhà đầu tư cá nhân làm khuếch đại điều kiện cần thứ hai (tức là niềm tin không đồng nhất). Các nghiên cứu về thị trường Việt Nam đã ghi nhận hành vi bầy đàn đáng kể [@vo2017further; @vo2015foreign], giao dịch theo tâm lý [@phan2023role; @nguyen2018search], và bất cân xứng thông tin giữa nhà đầu tư trong nước và nước ngoài [@vo2017foreign]. Những đặc điểm hành vi này tự nhiên tạo ra mức phân tán trong định giá của nhà đầu tư rộng hơn so với các thị trường do nhà đầu tư tổ chức chi phối, vốn có khả năng tiếp cận các khung phân tích và nguồn thông tin tương tự nhau.@tbl-divop-vietnam-us so sánh các đặc điểm thể chế chủ chốt liên quan đến khung DIVOP giữa Việt Nam và Hoa Kỳ.| Đặc điểm | Việt Nam (HOSE/HNX) | Hoa Kỳ (NYSE/NASDAQ) ||:-----------------------|:-----------------------|:-----------------------|| Bán khống | Áp dụng từ tháng 1/2025 (hạn chế) | Được phép (Reg SHO từ 2005) || Tỷ trọng nhà đầu tư cá nhân trong khối lượng | \~80-85% | \~25% || Chu kỳ thanh toán | T+2 (dự kiến T+1 vào 2026) | T+1 (từ tháng 5/2024) || Biên độ giá hằng ngày | $\pm$ 7% (HOSE), $\pm$ 10% (HNX) | Không có || Mức trần sở hữu nước ngoài | 49% (hầu hết các ngành) | Không có || Độ phủ nhà phân tích trung bình (VN30) | 5-10 nhà phân tích | 15-25 nhà phân tích || Báo cáo hằng quý bắt buộc | Có (từ 2012) | Có || Thị trường quyền chọn/phái sinh | Hợp đồng tương lai VN30 (từ 2017) | Quyền chọn/hợp đồng tương lai phong phú |: So sánh thể chế giữa Việt Nam và Hoa Kỳ liên quan đến sự phân kỳ quan điểm {#tbl-divop-vietnam-us}Biên độ giá hằng ngày ($\pm$ 7% trên HOSE và $\pm$ 10% trên HNX) tạo ra một cơ chế bổ sung làm khuếch đại sự phân kỳ quan điểm. Khi một cổ phiếu chạm biên độ giá, các nhà đầu tư muốn giao dịch theo hướng của biên độ không thể thực hiện được, dẫn đến lệnh chưa khớp tích tụ và việc khám phá giá bị trì hoãn. Đặc điểm thể chế này có thể tạo ra các đỉnh nhọn ngắn hạn trong DIVOP đo được, phản ánh ma sát do biên độ gây ra chứ không phải sự bất đồng thực sự. Chúng ta xử lý vấn đề này trong phương pháp thực nghiệm bằng cách đánh dấu các ngày chạm biên độ và thực hiện các kiểm tra độ vững loại trừ những quan sát này.# Nguồn dữ liệu và xây dựng mẫu {#sec-data}## Nguồn dữ liệuViệc xây dựng các biến đại diện DIVOP cho thị trường Việt Nam đòi hỏi dữ liệu giao dịch cổ phiếu hằng ngày và, đối với các thước đo phân tán của nhà phân tích, dữ liệu dự báo của từng nhà phân tích. Chúng ta lấy toàn bộ dữ liệu từ [DataCore.vn](https://datacore.vn/en), nguồn cung cấp độ phủ của mọi chứng khoán niêm yết trên HOSE, HNX và sàn UPCoM (Unlisted Public Company Market). @tbl-divop-data-sources tóm tắt các bộ dữ liệu và biến chính được dùng trong nghiên cứu này.| Bộ dữ liệu | Biến chính | Tần suất ||:-----------------------|:-----------------------|:-----------------------|| Giao dịch cổ phiếu hằng ngày | Giá đóng cửa, giá cao nhất, giá thấp nhất, giá mở cửa, khối lượng, số cổ phiếu đang lưu hành, giá điều chỉnh, giá mua, giá bán | Hằng ngày || Hành động doanh nghiệp | Cổ tức, chia tách cổ phiếu, cổ phiếu thưởng, phát hành quyền mua | Theo sự kiện || Thông tin doanh nghiệp | Mã sàn, phân loại ngành (ICB), ngày niêm yết, ngày hủy niêm yết | Tĩnh/Định kỳ || Dự báo của nhà phân tích | Dự báo EPS của từng nhà phân tích, ngày công bố, ngày kết thúc kỳ tài chính, mã nhà phân tích, tên công ty môi giới | Theo từng dự báo || Chỉ số thị trường | Lợi nhuận hằng ngày của VN-Index, VN30, HNX-Index | Hằng ngày || Sở hữu nước ngoài | Khối lượng mua/bán của nhà đầu tư nước ngoài, tỷ lệ sở hữu nước ngoài, room ngoại còn lại | Hằng ngày |: Nguồn dữ liệu và các biến chính để xây dựng biến đại diện DIVOP {#tbl-divop-data-sources}## Xây dựng mẫuChúng ta xây dựng mẫu bằng các bộ lọc sau, áp dụng tuần tự:```{python}#| label: sample-construction#| code-summary: "Sample construction and initial data loading"import pandas as pdimport numpy as npfrom datetime import datetime, timedeltafrom sklearn.linear_model import LinearRegressionfrom scipy import stats as scipy_statsimport matplotlib.pyplot as pltimport matplotlib.dates as mdatesimport seaborn as snsimport warningswarnings.filterwarnings('ignore')# =============================================================================# Configuration Parameters# =============================================================================# Users can modify these parameters to adjust the methodologyCONFIG = {# Sample period'beg_date': '2007-01-01','end_date': '2024-12-31',# Estimation windows (in trading days)'est_window': 60, # Rolling window for SUV and volatility'detrend_window': 180, # Window for DTO detrending median'lag': 7, # Lag for DTO detrending'gap': 5, # Gap between estimation period and event date# Filters'min_price': 1000, # Minimum price in VND'min_volume_days': 0.8, # Min fraction of non-zero volume days in window'min_analysts': 3, # Minimum number of analysts for DISP'max_spread_pct': 0.50, # Maximum bid-ask spread as fraction of midpoint'forecast_carry_days': 105,# Days to carry forward stale analyst forecasts# Exchange identifiers'exchanges': ['HOSE', 'HNX'],# Price limit thresholds (for flagging)'price_limit_hose': 0.07,'price_limit_hnx': 0.10,}print("Configuration parameters loaded successfully.")print(f"Sample period: {CONFIG['beg_date']} to {CONFIG['end_date']}")print(f"Estimation window: {CONFIG['est_window']} trading days")print(f"Detrending window: {CONFIG['detrend_window']} trading days")```Tập mẫu bao gồm mọi cổ phiếu phổ thông niêm yết trên HOSE và HNX trong giai đoạn từ tháng 1 năm 2007 đến tháng 12 năm 2024. Chúng ta bắt đầu từ năm 2007 thay vì từ khi thị trường hình thành (2000 đối với HOSE, 2005 đối với HNX) vì hai lý do. Thứ nhất, những năm đầu của thị trường Việt Nam có số doanh nghiệp niêm yết cực nhỏ (dưới 30 doanh nghiệp trên HOSE cho đến năm 2005), khiến phân tích mặt cắt ngang không đáng tin cậy. Thứ hai, chất lượng và tính nhất quán của dữ liệu cải thiện đáng kể sau đợt mở rộng thị trường 2006-2007, trong đó số doanh nghiệp niêm yết trên HOSE tăng từ khoảng 40 lên hơn 100.Chúng ta áp dụng các bộ lọc sau để xây dựng mẫu phân tích:1. **Bộ lọc loại chứng khoán.** Chúng ta chỉ giữ lại cổ phiếu phổ thông, loại trừ cổ phiếu ưu đãi, quỹ hoán đổi danh mục (ETF), chứng quyền có bảo đảm và chứng chỉ tiền gửi. Điều này tương tự bộ lọc chuẩn trong các nghiên cứu ở Hoa Kỳ, vốn giới hạn ở mã cổ phiếu CRSP 10 và 11.2. **Bộ lọc sàn giao dịch.** Chúng ta đưa vào các cổ phiếu niêm yết trên HOSE và HNX nhưng loại trừ các chứng khoán UPCoM trong phân tích cơ sở. UPCoM là địa điểm giao dịch dựa trên đăng ký, với yêu cầu niêm yết ít chặt chẽ hơn và thanh khoản thấp hơn đáng kể, có thể đưa nhiễu vào các thước đo dựa trên khối lượng và chênh lệch giá. Chúng ta đưa UPCoM vào các kiểm tra độ vững.3. **Bộ lọc giá.** Chúng ta loại trừ các quan sát cổ phiếu-ngày có giá đóng cửa dưới 1,000 VND. Ngưỡng này phục vụ cùng mục đích với việc loại trừ "cổ phiếu penny" phổ biến trong các nghiên cứu ở Hoa Kỳ (thường là ngưỡng \$1 hoặc \$5) và giúp giảm ảnh hưởng của lợi nhuận phần trăm và chênh lệch giá cực đoan ở các mức giá rất thấp.4. **Hoạt động giao dịch tối thiểu.** Với các thước đo dựa trên khối lượng, chúng ta yêu cầu cổ phiếu có khối lượng giao dịch khác không trong ít nhất 80% số ngày giao dịch của mỗi cửa sổ ước lượng. Bộ lọc này loại bỏ những chứng khoán giao dịch thưa thớt nhất, vốn khiến các thước đo dựa trên vòng quay không đáng tin cậy.```{python}#| label: load-and-filter#| code-summary: "Load and filter daily stock data"def load_daily_data(config):""" Load daily stock trading data from DataCore.vn. In practice, this function connects to the DataCore API or reads from a local database/CSV. Here we document the expected schema. Expected columns: - ticker: str, stock ticker symbol (e.g., 'VCB', 'HPG', 'VNM') - date: datetime, trading date - open, high, low, close: float, daily OHLC prices (VND) - volume: int, trading volume (shares) - shares_outstanding: int, total shares outstanding - adjusted_close: float, price adjusted for corporate actions - adj_factor: float, cumulative adjustment factor - bid, ask: float, best bid/ask at close - exchange: str, exchange code ('HOSE', 'HNX', 'UPCOM') - industry_icb: str, ICB industry classification code - foreign_buy_vol, foreign_sell_vol: int, foreign investor volumes - foreign_ownership_pct: float, foreign ownership percentage """# =========================================================================# Replace with actual DataCore API call:# from datacore import Client# client = Client(api_key='YOUR_KEY')# df = client.daily_stock(# start=config['beg_date'], end=config['end_date'],# exchanges=config['exchanges']# )# =========================================================================print("Connect to DataCore.vn and load daily stock data.")print("Expected schema: ticker, date, open, high, low, close, volume,")print(" shares_outstanding, adjusted_close, adj_factor, bid, ask,")print(" exchange, industry_icb, foreign_buy_vol, foreign_sell_vol,")print(" foreign_ownership_pct")returnNone# Replace with actual datadef apply_sample_filters(df, config):"""Apply sequential sample construction filters."""print("\n=== Sample Construction ===") n0 =len(df)# Date filter df = df[(df['date'] >= config['beg_date']) & (df['date'] <= config['end_date'])].copy()print(f"[1] Date filter: {len(df):,} obs (from {n0:,})")# Exchange filter df = df[df['exchange'].isin(config['exchanges'])].copy()print(f"[2] Exchange filter ({config['exchanges']}): {len(df):,} obs")# Price filter df = df[df['close'] >= config['min_price']].copy()print(f"[3] Price >= {config['min_price']:,} VND: {len(df):,} obs")# Compute daily return from adjusted prices df = df.sort_values(['ticker', 'date']) df['ret'] = df.groupby('ticker')['adjusted_close'].pct_change()# Flag price limit hits df['limit_hit'] = ( ((df['exchange'] =='HOSE') & (df['ret'].abs() >= config['price_limit_hose'] -0.001)) | ((df['exchange'] =='HNX') & (df['ret'].abs() >= config['price_limit_hnx'] -0.001)) ) n_tickers = df['ticker'].nunique()print(f"\nFinal sample: {len(df):,} stock-day obs, "f"{n_tickers} unique tickers")print(f"Limit-hit days: {df['limit_hit'].sum():,} "f"({100*df['limit_hit'].mean():.2f}%)")return df```## Điều chỉnh theo hành động doanh nghiệp {#sec-corp-actions}Điều chỉnh đúng đắn theo các hành động doanh nghiệp là yếu tố then chốt đối với các thước đo DIVOP dựa trên khối lượng, vì các sự kiện như chia tách cổ phiếu, phát hành cổ phiếu thưởng và phát hành quyền mua làm thay đổi số cổ phiếu đang lưu hành và có thể tạo ra các đỉnh nhọn giả tạo trong vòng quay đo được. Chúng ta cần dùng các hệ số điều chỉnh tích lũy tính đến cổ tức bằng cổ phiếu (cổ phiếu thưởng), chia tách cổ phiếu, phát hành quyền mua và cổ tức tiền mặt (chỉ điều chỉnh giá). Chúng ta dùng các hệ số này để xây dựng khối lượng điều chỉnh và số cổ phiếu đang lưu hành điều chỉnh:$$\text{AdjVolume}_{i,t} = \text{Volume}_{i,t} \times \text{CumAdjFactor}_{i,t}$$$$\text{AdjSharesOut}_{i,t} = \text{SharesOut}_{i,t} \times \text{CumAdjFactor}_{i,t}$$Điều này bảo đảm tỷ lệ vòng quay nhất quán giữa các sự kiện hành động doanh nghiệp.```{python}#| label: corp-action#| code-summary: "Corporate action adjustment"def adjust_for_corporate_actions(df):"""Apply cumulative adjustment factors to volume and shares outstanding.""" df = df.copy() df['adj_volume'] = df['volume'] * df['adj_factor'] df['adj_shares_out'] = df['shares_outstanding'] * df['adj_factor']# Daily turnover ratio df['turnover'] = np.where( df['adj_shares_out'] >0, df['adj_volume'] / df['adj_shares_out'], np.nan )# Flag extreme turnover (> 50% of float) extreme = df['turnover'] >0.50if extreme.any():print(f"Warning: {extreme.sum()} obs with turnover > 50%, set to NaN") df.loc[extreme, 'turnover'] = np.nanreturn df```## Xây dựng lịch giao dịch {#sec-calendar}Phương pháp hồi quy trượt cho SUV và biến động đòi hỏi một lịch giao dịch bảo đảm mỗi cửa sổ ước lượng chứa chính xác số ngày giao dịch đã định. Chúng ta xây dựng lịch này trực tiếp từ các ngày giao dịch quan sát được.```{python}#| label: trading-calendar#| code-summary: "Build trading calendar for rolling estimation windows"def build_trading_calendar(df, config):""" Map each trading date to its estimation window [est_start, est_end]. For date t, the estimation window runs from t - gap - est_window to t - gap - 1 (in trading-day terms). """ trading_dates =sorted(df['date'].unique()) trading_dates = pd.Series(trading_dates) est_window = config['est_window'] gap = config['gap'] offset = est_window + gap records = []for i inrange(offset, len(trading_dates)): records.append({'date': trading_dates.iloc[i],'est_start': trading_dates.iloc[i - gap - est_window],'est_end': trading_dates.iloc[i - gap -1] }) calendar = pd.DataFrame(records)print(f"Trading calendar: {len(calendar)} dates, "f"{calendar['date'].min()} to {calendar['date'].max()}")return calendar```# Các biến đại diện DIVOP dựa trên khối lượng {#sec-volume-based}## Động cơ lý thuyếtKhối lượng giao dịch từ lâu đã được công nhận là biến đại diện tự nhiên cho sự phân kỳ quan điểm của nhà đầu tư. Trong khung kỳ vọng hợp lý của @milgrom1982information, giao dịch chỉ xảy ra khi các nhà đầu tư bất đồng về giá trị của một chứng khoán (tức là một "định lý không giao dịch" hàm ý, theo phản đảo, rằng khối lượng giao dịch quan sát được phải phản ánh một dạng niềm tin không đồng nhất nào đó). @harris1993differences và @kandel1995differential hình thức hóa trực giác này, cho thấy khối lượng giao dịch có quan hệ cùng chiều với mức phân tán của niềm tin ban đầu của nhà đầu tư và với mức độ thông tin công khai được diễn giải khác nhau.Khó khăn khi dùng khối lượng giao dịch thô làm biến đại diện DIVOP là khối lượng còn chịu tác động của các yếu tố không liên quan đến bất đồng, bao gồm tái cân bằng danh mục, yêu cầu về thanh khoản, bán để ghi nhận lỗ thuế và các hiệu ứng tái cơ cấu chỉ số. @garfinkel2009measuring đề xuất hai cách để tách thành phần bất đồng khỏi khối lượng thô. Cách thứ nhất, **Khối lượng không được giải thích (DTO)**, loại bỏ các hiệu ứng khối lượng toàn thị trường và xu hướng dài hạn. Cách thứ hai, **Khối lượng không được giải thích đã chuẩn hóa (SUV)**, kiểm soát thêm hàm lượng thông tin của lợi nhuận thông qua một hồi quy mặt cắt ngang, tách riêng thành phần "bất đồng thuần túy" của hoạt động giao dịch.## Khối lượng không được giải thích (DTO) {#sec-dto}### Phương pháp xây dựngViệc xây dựng thước đo Khối lượng không được giải thích gồm bốn bước.**Bước 1: Tính vòng quay hằng ngày cấp doanh nghiệp.** Với mỗi cổ phiếu $i$ vào ngày $t$:$$\text{Turn}_{i,t} = \frac{\text{AdjVolume}_{i,t}}{\text{AdjSharesOut}_{i,t}}$$**Bước 2: Tính vòng quay toàn thị trường.** Chúng ta tính vòng quay tổng hợp của mọi cổ phiếu phổ thông dưới dạng trung bình theo trọng số vốn hóa:$$\text{MktTurn}_{t} = \frac{\sum_{i} \text{AdjVolume}_{i,t}}{\sum_{i} \text{AdjSharesOut}_{i,t}}$$Khác với phương pháp ở Hoa Kỳ vốn tính vòng quay thị trường chỉ trên các cổ phiếu NYSE/AMEX và áp dụng một điều chỉnh tỷ lệ cho các chứng khoán NASDAQ [theo @anderson2005market], chúng ta tính vòng quay thị trường trên mọi cổ phiếu phổ thông của HOSE và HNX mà không có bất kỳ việc điều chỉnh tỷ lệ khối lượng riêng cho từng sàn nào. Cả hai sàn của Việt Nam đều vận hành như thị trường dẫn dắt bởi lệnh (HOSE dùng khớp lệnh liên tục; HNX dùng kết hợp khớp lệnh liên tục và đấu giá định kỳ) mà không có vấn đề tính trùng của thị trường nhà tạo lập (dealer market), vấn đề vốn đòi hỏi điều chỉnh khối lượng NASDAQ trong các nghiên cứu ở Hoa Kỳ.**Bước 3: Tính vòng quay đã điều chỉnh theo thị trường.**$$\text{MATO}_{i,t} = \text{Turn}_{i,t} - \text{MktTurn}_{t}$$**Bước 4: Loại bỏ xu hướng bằng trung vị trượt.** Để loại bỏ các xu hướng dài hạn trong hoạt động giao dịch đặc thù của doanh nghiệp:$$\text{DTO}_{i,t} = \text{MATO}_{i,t} - \text{Median}_{180}(\text{MATO}_{i,t-7})$$trong đó $\text{Median}_{180}(\text{MATO}_{i,t-7})$ là trung vị của vòng quay đã điều chỉnh theo thị trường trong cửa sổ 180 ngày giao dịch kết thúc 7 ngày trước ngày $t$. Độ trễ 7 ngày ngăn vòng quay của ngày hiện tại ảnh hưởng đến mức cơ sở dùng để loại bỏ xu hướng của chính nó.```{python}#| label: dto-construction#| code-summary: "Construct the Unexplained Volume (DTO) measure"def compute_market_turnover(df):"""Compute daily market-wide turnover across all stocks.""" mkt_turn = df.groupby('date').apply(lambda x: x['adj_volume'].sum() / x['adj_shares_out'].sum()if x['adj_shares_out'].sum() >0else np.nan ).reset_index() mkt_turn.columns = ['date', 'market_turnover']return mkt_turndef compute_dto(df, config):""" Construct Unexplained Volume (DTO). Steps: 1. Subtract market turnover -> MATO 2. Rolling 180-day median of MATO (lagged 7 days) -> trend 3. DTO = MATO - trend """ detrend_window = config['detrend_window'] lag = config['lag']# Market turnover mkt_turn = compute_market_turnover(df) df = df.merge(mkt_turn, on='date', how='left')# Market-adjusted turnover df['mato'] = df['turnover'] - df['market_turnover']# Rolling median with lag, computed per stock df = df.sort_values(['ticker', 'date'])def _rolling_median_lagged(group): mato = group['mato'] med = mato.rolling( window=detrend_window, min_periods=int(detrend_window *0.5) ).median()return med.shift(lag) df['mato_trend'] = ( df.groupby('ticker', group_keys=False) .apply(lambda g: _rolling_median_lagged(g)) )# DTO df['dto'] = df['mato'] - df['mato_trend']print("DTO construction complete.")print(f" Non-missing: {df['dto'].notna().sum():,}")print(f" Mean: {df['dto'].mean():.6f}, Std: {df['dto'].std():.6f}")return df```### Những lưu ý riêng của Việt Nam đối với DTOMột số đặc điểm của thị trường Việt Nam cần được chú ý khi xây dựng DTO:1. **Không cần điều chỉnh khối lượng kiểu NASDAQ.** Cả HOSE và HNX đều là thị trường đấu giá dẫn dắt bởi lệnh. Điều chỉnh tính trùng áp dụng cho các chứng khoán NASDAQ trong các nghiên cứu ở Hoa Kỳ là không cần thiết.2. **Cổ phiếu giao dịch thưa thớt.** Một tỷ lệ đáng kể cổ phiếu niêm yết của Việt Nam, đặc biệt trên HNX, có thể có khối lượng bằng không trong nhiều ngày giao dịch. Với các cổ phiếu giao dịch không liên tục, trung vị trượt có thể bị chệch về không, khiến DTO kém thông tin hơn. Chúng ta yêu cầu ít nhất 80% số ngày có khối lượng khác không trong mỗi cửa sổ ước lượng.3. **Tác động của biên độ giá lên khối lượng.** Khi một cổ phiếu chạm biên độ giá hằng ngày, các lệnh chưa khớp tích tụ và khối lượng ghi nhận có thể thấp hơn khối lượng khớp thực. Ngày hôm sau thường xuất hiện hiệu ứng "bắt kịp". Các nhà nghiên cứu nên cân nhắc đánh dấu các ngày chạm biên độ.4. **Phân rã giao dịch của nhà đầu tư nước ngoài.** DataCore cung cấp khối lượng theo loại nhà đầu tư (nước ngoài so với trong nước). Các nhà nghiên cứu có thể muốn xây dựng các thước đo DTO riêng cho khối lượng của nhà đầu tư nước ngoài và trong nước, hoặc dùng tỷ lệ khối lượng nước ngoài trên trong nước như một chiều bổ sung của sự bất đồng.## Khối lượng không được giải thích đã chuẩn hóa (SUV) {#sec-suv}### Phương pháp xây dựngThước đo Khối lượng không được giải thích đã chuẩn hóa, do @garfinkel2009measuring đề xuất, tách riêng thành phần bất đồng của khối lượng bằng cách kiểm soát một cách tường minh hàm lượng thông tin của lợi nhuận. Ý tưởng là khối lượng giao dịch có cả thành phần **thanh khoản** lẫn thành phần **thông tin** tương quan với độ lớn và dấu của lợi nhuận. Bằng cách hồi quy vòng quay theo lợi nhuận có dấu và lấy phần dư chuẩn hóa, SUV nắm bắt khối lượng do bất đồng gây ra sau khi kiểm soát cả xu hướng thanh khoản lẫn giao dịch dựa trên thông tin.Với mỗi cổ phiếu $i$, tại mỗi ngày giao dịch $t$, chúng ta ước lượng bằng dữ liệu từ cửa sổ ước lượng $[\tau_1, \tau_2]$:$$\text{Turn}_{i,s} = \alpha_i + \beta_i^{+} \cdot \text{RetPos}_{i,s} + \beta_i^{-} \cdot \text{RetNeg}_{i,s} + \epsilon_{i,s}, \quad s \in [\tau_1, \tau_2]$$ {#eq-suv-regression}trong đó $\text{RetPos}_{i,s} = |r_{i,s}| \cdot \mathbf{1}(r_{i,s} > 0)$ và $\text{RetNeg}_{i,s} = |r_{i,s}| \cdot \mathbf{1}(r_{i,s} < 0)$.Khối lượng không được giải thích đã chuẩn hóa vào ngày $t$ là:$$\text{SUV}_{i,t} = \frac{\text{Turn}_{i,t} - \hat{\text{Turn}}_{i,t}}{\hat{\sigma}_{\epsilon,i}}$$ {#eq-suv}trong đó $\hat{\text{Turn}}_{i,t}$ là vòng quay dự báo và $\hat{\sigma}_{\epsilon,i}$ là RMSE từ @eq-suv-regression.Đặc tả bất đối xứng với các hệ số riêng cho lợi nhuận dương và âm phản ánh việc quan hệ khối lượng-lợi nhuận khác nhau theo dấu của lợi nhuận. Ở Hoa Kỳ, áp lực mua có xu hướng tạo ra khối lượng lớn hơn áp lực bán do các ma sát bán khống. Ở Việt Nam, nơi bán khống không khả dụng cho đến năm 2025, sự bất đối xứng này được kỳ vọng còn rõ rệt hơn vì mọi hoạt động bán đều bị giới hạn ở các cổ đông hiện hữu.```{python}#| label: suv-construction#| code-summary: "Construct Standardized Unexplained Volume (SUV)"def compute_suv(df, calendar, config):""" Compute Standardized Unexplained Volume via rolling regressions. For each stock-date, regress Turn on RetPos and RetNeg over the estimation window, then compute SUV = (actual - predicted) / RMSE. """ est_window = config['est_window'] min_obs =int(est_window * config['min_volume_days'])# Prepare signed return components df = df.copy() df['ret_pos'] = np.where(df['ret'] >0, np.abs(df['ret']), 0.0) df['ret_neg'] = np.where( (df['ret'] <0) & df['ret'].notna(), np.abs(df['ret']), 0.0 ) results = [] grouped = {t: g for t, g in df.groupby('ticker')}for _, cal_row in calendar.iterrows(): dt = cal_row['date'] est_s, est_e = cal_row['est_start'], cal_row['est_end']for ticker, tdata in grouped.items():# Estimation window est = tdata[ (tdata['date'] >= est_s) & (tdata['date'] <= est_e) ].dropna(subset=['turnover', 'ret_pos', 'ret_neg'])iflen(est) < min_obs:continue# Event date evt = tdata[tdata['date'] == dt]if evt.empty or evt['turnover'].isna().all():continue# OLS: Turn = alpha + beta_pos * RetPos + beta_neg * RetNeg X = est[['ret_pos', 'ret_neg']].values y = est['turnover'].values reg = LinearRegression().fit(X, y) y_hat = reg.predict(X) rmse = np.sqrt(np.mean((y - y_hat) **2))if rmse <=0:continue# Predict and standardize for event date X_evt = evt[['ret_pos', 'ret_neg']].values pred = reg.predict(X_evt)[0] actual = evt['turnover'].values[0] suv = (actual - pred) / rmse results.append({'ticker': ticker, 'date': dt,'suv': suv,'predicted_turnover': pred,'rmse_turn': rmse,'n_est': len(est),'alpha_turn': reg.intercept_,'beta_pos': reg.coef_[0],'beta_neg': reg.coef_[1], }) suv_df = pd.DataFrame(results)print(f"SUV: {len(suv_df):,} stock-date obs")print(f" Mean: {suv_df['suv'].mean():.4f}, "f"Median: {suv_df['suv'].median():.4f}")return suv_df```### Diễn giải các hệ số hồi quy SUVCác hệ số ước lượng từ @eq-suv-regression cung cấp thông tin về vi cấu trúc thị trường. @garfinkel2009measuring báo cáo $\hat{\beta}^{+} > \hat{\beta}^{-}$ đối với hầu hết cổ phiếu Hoa Kỳ. Ở Việt Nam, chúng ta kỳ vọng sự bất đối xứng này còn mạnh hơn vì:- **Không có bán khống (trước 2025):** Mọi lệnh bán đều do cổ đông hiện hữu thực hiện, làm hạn chế phản ứng của khối lượng đối với lợi nhuận âm.- **Thanh toán T+2:** Nhà đầu tư không thể tái đầu tư ngay tiền bán, làm giảm thêm khối lượng bên bán.- **Biên độ giá:** Biên độ hằng ngày $\pm$ 7% (HOSE) và $\pm$ 10% (HNX) cắt cụt phân phối lợi nhuận, nén khoảng biến thiên của cả hai biến hồi quy.Các nhà nghiên cứu nên báo cáo thống kê mô tả của $(\hat{\alpha}, \hat{\beta}^{+}, \hat{\beta}^{-}, R^2)$ theo mặt cắt ngang và theo thời gian.```{python}#| label: suv-diagnostics#| code-summary: "Diagnostic statistics for SUV turnover regressions"def suv_diagnostics(suv_df):"""Report cross-sectional summary of SUV regression parameters."""print("\n=== SUV Regression Diagnostics ===") params = ['alpha_turn', 'beta_pos', 'beta_neg']print(suv_df[params].describe( percentiles=[.05, .25, .50, .75, .95] ).T.to_string(float_format='{:.6f}'.format))# Asymmetry test diff = suv_df['beta_pos'] - suv_df['beta_neg']print(f"\nbeta_pos - beta_neg: mean = {diff.mean():.6f}, "f"frac > 0 = {(diff >0).mean():.3f}")```# Các biến đại diện DIVOP dựa trên biến động {#sec-volatility}## Biến động lợi nhuận tổng {#sec-total-vol}### Động cơ lý thuyếtBiến động lợi nhuận cổ phiếu đóng vai trò biến đại diện cho sự phân kỳ quan điểm qua nhiều kênh. @shalen1993volume xây dựng một mô hình trong đó cả khối lượng lẫn biến động đều tăng theo mức phân tán niềm tin của nhà đầu tư. @scheinkman2003overconfidence dự đoán rằng biến động cao hơn phản ánh thành phần giao dịch đầu cơ do các nhà đầu tư tự tin thái quá bất đồng về giá trị thúc đẩy. Về mặt thực nghiệm, @boehme2006short và @chatterjee2012takeovers dùng biến động đặc thù làm biến đại diện DIVOP và thấy nó tương quan dương với các thước đo bất đồng khác và gắn với lợi nhuận về sau thấp hơn khi các hạn chế bán khống có hiệu lực ràng buộc.### Xây dựngBiến động lợi nhuận tổng là độ lệch chuẩn của lợi nhuận hằng ngày trong cửa sổ ước lượng trượt:$$\text{VOLATILITY}_{i,t} = \sqrt{\frac{1}{N_i - 1} \sum_{s \in [\tau_1, \tau_2]} (r_{i,s} - \bar{r}_i)^2}$$ {#eq-volatility}trong đó $N_i$ là số quan sát lợi nhuận không bị thiếu của cổ phiếu $i$ trong cửa sổ $[\tau_1, \tau_2]$.## Biến động đặc thù (IVOL) {#sec-ivol}Biến động đặc thù tách riêng biến thiên lợi nhuận đặc thù của doanh nghiệp bằng cách loại bỏ thành phần hệ thống được giải thích bởi biến động thị trường. Chúng ta tính IVOL từ phần dư của mô hình thị trường:$$r_{i,s} = \alpha_i + \beta_i \cdot r_{m,s} + \epsilon_{i,s}, \quad s \in [\tau_1, \tau_2]$$ {#eq-market-model}$$\text{IVOL}_{i,t} = \text{Std}(\hat{\epsilon}_{i,s})$$ {#eq-ivol}Các nhà nghiên cứu có thể mở rộng sang mô hình ba nhân tố hoặc năm nhân tố của @fama1993common bằng các danh mục nhân tố Việt Nam được xây dựng ở những phần khác trong cuốn sách này. Một mô hình nhân tố phong phú hơn cho các ước lượng IVOL tách biệt tốt hơn sự bất đồng thực sự mang tính đặc thù, với cái giá là phải xây dựng các danh mục nhân tố.```{python}#| label: volatility-construction#| code-summary: "Construct total and idiosyncratic volatility"def compute_volatility(df, calendar, config):""" Compute total return volatility and idiosyncratic volatility via rolling estimation windows. Total vol = std(returns) in window. IVOL = std(residuals) from market model regression. """ est_window = config['est_window'] min_obs =int(est_window * config['min_volume_days'])# Value-weighted market returndef _vw_ret(g): valid = g.dropna(subset=['ret'])if valid.empty:return np.nan w = valid['adj_shares_out'] * valid['close']return np.average(valid['ret'], weights=w) mkt_ret = df.groupby('date').apply(_vw_ret).reset_index() mkt_ret.columns = ['date', 'mkt_ret'] df = df.merge(mkt_ret, on='date', how='left') results = [] grouped = {t: g for t, g in df.groupby('ticker')}for _, cal_row in calendar.iterrows(): dt = cal_row['date'] est_s, est_e = cal_row['est_start'], cal_row['est_end']for ticker, tdata in grouped.items(): est = tdata[ (tdata['date'] >= est_s) & (tdata['date'] <= est_e) ].dropna(subset=['ret', 'mkt_ret'])iflen(est) < min_obs:continue# Total volatility total_vol = est['ret'].std()# Market model -> IVOL X = est[['mkt_ret']].values y = est['ret'].values reg = LinearRegression().fit(X, y) resid = y - reg.predict(X) ivol = np.std(resid, ddof=1) results.append({'ticker': ticker, 'date': dt,'total_volatility': total_vol,'idio_volatility': ivol,'market_beta': reg.coef_[0],'market_alpha': reg.intercept_,'r_squared_mm': reg.score(X, y),'n_vol': len(est), }) vol_df = pd.DataFrame(results)print(f"Volatility: {len(vol_df):,} stock-date obs")print(f" Total vol (ann. mean): "f"{vol_df['total_volatility'].mean() * np.sqrt(252):.4f}")print(f" IVOL (ann. mean): "f"{vol_df['idio_volatility'].mean() * np.sqrt(252):.4f}")return vol_df```### Những lưu ý riêng của Việt Nam đối với biến động1. **Biên độ giá làm nén biến động đo được.** Biên độ hằng ngày $\pm$ 7% (HOSE) và $\pm$ 10% (HNX) cắt cụt phân phối lợi nhuận một cách cơ học, dẫn đến đánh giá thấp biến động thực. Vào các ngày chạm biên độ, lợi nhuận cân bằng thực có thể vượt lợi nhuận quan sát được. Các nhà nghiên cứu cần lưu ý rằng các thước đo DIVOP dựa trên biến động có thể bị chệch xuống đối với các cổ phiếu thường xuyên chạm biên độ.2. **Sự tập trung của VN-Index.** VN-Index có mức độ tập trung cao, 10 cổ phiếu hàng đầu thường chiếm 50-60% trọng số chỉ số. Với các cổ phiếu vốn hóa nhỏ và vừa, lợi nhuận thị trường trọng số bằng nhau hoặc một chỉ số tổng hợp HOSE+HNX có thể cung cấp nhân tố thị trường tốt hơn trong @eq-market-model.3. **Giao dịch thưa thớt và lợi nhuận không đồng bộ.** Với các cổ phiếu giao dịch thưa thớt, các ngày có lợi nhuận bằng không liên tiếp có thể làm giảm biến động đo được. Điều chỉnh của @dimson1979risk (đưa lợi nhuận thị trường trễ và dẫn trước vào mô hình thị trường) có thể giúp hiệu chỉnh thiên lệch giao dịch không đồng bộ trong ước lượng beta, dù tác động của nó lên IVOL thường nhỏ.# Các biến đại diện DIVOP dựa trên chênh lệch giá và thanh khoản {#sec-spread}## Chênh lệch giá mua–bán (BASPREAD) {#sec-baspread}### Động cơ lý thuyếtChênh lệch giá mua–bán phản ánh chi phí lựa chọn bất lợi mà các bên cung cấp lệnh giới hạn phải gánh. Khi nhà đầu tư có niềm tin không đồng nhất, mỗi giao dịch có nhiều khả năng truyền tải thông tin riêng hơn, làm tăng thành phần lựa chọn bất lợi của chênh lệch giá. @handa2003quote chỉ ra rằng trong các thị trường dẫn dắt bởi lệnh, chênh lệch giá nới rộng khi sự phân kỳ quan điểm tăng vì các bên cung cấp lệnh giới hạn đối mặt rủi ro lớn hơn là bị các nhà giao dịch có thông tin khai thác. @chung2014simple chứng minh rằng chênh lệch giá mua–bán đóng cửa từ dữ liệu hằng ngày cung cấp xấp xỉ đáng tin cậy cho chênh lệch hiệu dụng trong ngày.### Xây dựngChúng ta tính chênh lệch giá mua–bán theo tỷ lệ bằng dữ liệu báo giá cuối ngày:$$\text{BASPREAD}_{i,t} = \frac{\text{Ask}_{i,t} - \text{Bid}_{i,t}}{\text{Midpoint}_{i,t}}$$ {#eq-baspread}trong đó $\text{Midpoint}_{i,t} = (\text{Ask}_{i,t} + \text{Bid}_{i,t}) / 2$. Khi không có giá mua và giá bán cuối ngày, chúng ta dùng biên độ cao–thấp trong ngày làm phương án dự phòng. Theo @chung2014simple, chúng ta xóa các quan sát mà cả Bid và Ask đều bằng không, và những quan sát mà chênh lệch giá vượt quá 50% điểm giữa.## Phi thanh khoản Amihud (ILLIQ) {#sec-amihud}Tỷ số @amihud2002illiquidity đo lường tác động giá của dòng lệnh:$$\text{ILLIQ}_{i,t} = \frac{|r_{i,t}|}{\text{DolVol}_{i,t}}$$ {#eq-amihud}trong đó $\text{DolVol}_{i,t} = \text{Volume}_{i,t} \times \text{Price}_{i,t}$ (tính bằng tỷ VND để thu nhỏ thang đo). ILLIQ cao hơn phản ánh bất cân xứng thông tin lớn hơn. Chúng ta lấy trung bình các tỷ số hằng ngày theo từng tháng và dùng phép biến đổi logarit vì phân phối lệch phải nặng.```{python}#| label: spread-illiq#| code-summary: "Construct bid-ask spread and Amihud illiquidity"def compute_spread_and_illiq(df, config):"""Compute bid-ask spread (BASPREAD) and Amihud illiquidity.""" df = df.copy()# --- Bid-Ask Spread --- df['midpoint_ba'] = (df['ask'] + df['bid']) /2 df['baspread_ba'] = np.where( (df['ask'] >0) & (df['bid'] >0) & (df['midpoint_ba'] >0), (df['ask'] - df['bid']) / df['midpoint_ba'], np.nan )# Fallback: high/low range df['midpoint_hl'] = (df['high'] + df['low']) /2 df['baspread_hl'] = np.where( (df['high'] >0) & (df['low'] >0) & (df['midpoint_hl'] >0), (df['high'] - df['low']) / df['midpoint_hl'], np.nan ) df['baspread'] = df['baspread_ba'].fillna(df['baspread_hl']) df['midpoint'] = df['midpoint_ba'].fillna(df['midpoint_hl'])# Chung & Zhang (2009) filters bad = (df['baspread'].isna()) |\ (df['baspread'] > config['max_spread_pct']) |\ (df['baspread'] <0) df.loc[bad, 'baspread'] = np.nan# --- Amihud Illiquidity --- df['dollar_vol'] = df['volume'] * df['close'] /1e9 df['amihud_daily'] = np.where( df['dollar_vol'] >0, np.abs(df['ret']) / df['dollar_vol'], np.nan )print(f"BASPREAD: {df['baspread'].notna().sum():,} valid obs, "f"mean = {df['baspread'].mean():.6f}")print(f"AMIHUD: {df['amihud_daily'].notna().sum():,} valid obs, "f"mean = {df['amihud_daily'].mean():.6f}")return dfdef compute_amihud_monthly(df):"""Monthly Amihud = mean daily |ret|/dollar_vol (min 15 days).""" df = df.copy() df['ym'] = df['date'].dt.to_period('M') agg = df.groupby(['ticker', 'ym']).agg( illiq_mean=('amihud_daily', 'mean'), n_days=('amihud_daily', 'count'), ).reset_index() agg = agg[agg['n_days'] >=15].copy() agg['log_illiq'] = np.log(agg['illiq_mean'] +1e-10)return agg```### Những lưu ý riêng của Việt Nam đối với chênh lệch giá và thanh khoản1. **Biểu bước giá.** Việt Nam dùng bước giá thay đổi: 10 VND (giá \< 10,000), 50 VND (10,000--49,950) và 100 VND (≥ 50,000) trên HOSE. Các mức này đặt ra một sàn dưới cho chênh lệch giá chào của các cổ phiếu giá thấp. Các nhà nghiên cứu cần thận trọng khi diễn giải sự biến thiên của chênh lệch giá giữa các thập phân vị giá như phản ánh sự phân kỳ quan điểm thay vì cơ chế bước giá.2. **Cấu trúc thị trường dẫn dắt bởi lệnh.** Cả HOSE và HNX đều là các thị trường thuần dẫn dắt bởi lệnh, nơi các lệnh giới hạn công khai cung cấp thanh khoản. Điều này khiến phép xấp xỉ chênh lệch giá dựa trên CRSP của @chung2014simple là phù hợp.3. **Yêu cầu về lô giao dịch.** HOSE yêu cầu lô chuẩn 100 cổ phiếu cho giao dịch liên tục. Với các cổ phiếu giá cao, lô chuẩn đại diện cho một cam kết vốn lớn, có thể làm phồng chênh lệch giá chào so với chi phí giao dịch hiệu dụng.4. **Hiệu ứng đấu giá định kỳ.** Các phiên mở cửa và đóng cửa trên HOSE dùng đấu giá định kỳ, có thể tạo ra các báo giá mua–bán khác biệt đáng kể so với chênh lệch giá trong giao dịch liên tục.## Phi thanh khoản thực hiện: ILLIQ ít nhiễu hơn {#sec-divop-realized-illiq}Biến đại diện ILLIQ trong @eq-amihud tóm gọn cả một ngày biến động giá bằng một giá trị lợi nhuận tuyệt đối duy nhất. @lacava2026realized thay tử số đó bằng một ước lượng tần suất cao của chính biến thiên giá trong ngày, cho ra **Amihud thực hiện**$$\text{RILLIQ}_{i,t} = \sqrt{\frac{2}{\pi}}\,\frac{\sqrt{\text{RV}_{i,t}}}{\text{DolVol}_{i,t}},\qquad\text{RV}_{i,t} = \sum_{j=1}^{M} r_{i,t,j}^2$$ {#eq-divop-realized-illiq}với $r_{i,t,j}$ là lợi nhuận trong ngày trên $M$ khoảng lấy mẫu và $\sqrt{2/\pi}$ được chọn để @eq-divop-realized-illiq nằm trên cùng thang đo với @eq-amihud. Với 45 khoảng năm phút của HOSE, sai số đo lường tương đối của tử số giảm từ khoảng 76% xuống khoảng 11%. Phần suy dẫn và các giả định của hàm ước lượng này nằm trong @sec-liquidity-realized; phần triển khai trên HOSE nằm trong @sec-micro-realized-illiq.Lợi ích hiển nhiên là lợi ích chung của mọi biến đại diện DIVOP được dùng ở vế phải: một biến hồi quy sạch hơn gây thiên lệch suy giảm (attenuation) ít hơn, nên các hệ số dốc Fama-MacBeth trong @sec-applications được ước lượng gần giá trị thực hơn. Lập luận đó mang tính tổng quát và đã được nêu trong @sec-liquidity-realized.Lý do chương này cần một phần xử lý riêng là một vấn đề khác và cụ thể hơn, và nó ảnh hưởng đến những kết quả mà chương này thực sự báo cáo.### Nhiễu lấy mẫu chung làm nhiễm bẩn ma trận tương quanHãy xem các biến đại diện trong chương này được xây dựng từ đâu. ILLIQ lấy $|r_{i,t}|$ từ chuỗi lợi nhuận hằng ngày. TOTVOL lấy độ lệch chuẩn của *chính chuỗi đó*. IVOL lấy độ lệch chuẩn của phần dư của nó. Khi thiếu báo giá cuối ngày, BASPREAD dùng biên độ cao–thấp trong ngày làm phương án dự phòng, lấy từ cùng các bản ghi giá hằng ngày.Đây không phải là các phép đo độc lập. Một tháng mà lợi nhuận hằng ngày của doanh nghiệp tình cờ nhận những giá trị lớn sẽ cho ILLIQ đo được cao *và* TOTVOL đo được cao *và* IVOL đo được cao, không phải vì sự phân kỳ quan điểm thực của doanh nghiệp cao, mà vì cùng một mẫu hữu hạn các lợi nhuận hằng ngày là đầu vào của cả ba. Sai số lấy mẫu là chung giữa các biến đại diện, nên nó không triệt tiêu khi chúng được đặt tương quan với nhau hoặc được kết hợp.Điều này tác động trực tiếp đến hai việc mà chương làm. @sec-correlation báo cáo các tương quan Spearman giữa các biến đại diện DIVOP và diễn giải mô thức đó như bằng chứng về việc các biến đại diện nắm bắt những chiều nào của sự phân kỳ. @sec-empirical xây dựng một chỉ số tổng hợp bằng cách trích thành phần chính thứ nhất. Cả hai đều được tính trên cấu trúc tương quan của các biến đại diện đo được, và do đó đều hấp thụ bất kỳ tương quan nào mà các lợi nhuận hằng ngày dùng chung tạo ra.Mô phỏng dưới đây tách riêng hiệu ứng này. Biến động thực và khối lượng giao dịch thực được rút **độc lập** giữa các doanh nghiệp, nên mọi tương quan vượt mức đều có thể quy cho cách xây dựng chứ không phải yếu tố kinh tế. Biến đối chứng then chốt là cột `TOTVOL (disjoint)`, tính biến động từ lợi nhuận của một tháng *khác* của cùng doanh nghiệp: nó đo cùng biến động tiềm ẩn nhưng không chia sẻ nhiễu lấy mẫu với ILLIQ, nên khoảng cách giữa nó và tương quan cùng cửa sổ thông thường chính là thành phần cơ học.```{python}#| label: divop-realized-illiq-noise#| code-summary: "Shared sampling noise between ILLIQ and the volatility proxies"rng_ri = np.random.default_rng(2026)N_SIM, D_MONTH, M_HF =8000, 21, 45K_HF = np.sqrt(2/ np.pi)def simulate_month(vol_dispersion):""" One cross-section of firm-months. True volatility and true dollar volume are INDEPENDENT by construction, so any measured association between illiquidity and volatility beyond sqrt(sigma)/DolVol is an artefact. `vol_dispersion` is the cross-sectional sd of log dollar volume: wide for the full market, narrow within a size decile. """ sigma = np.exp(rng_ri.normal(np.log(0.022), 0.35, N_SIM)) dvol = np.exp(rng_ri.normal(np.log(5.0), vol_dispersion, N_SIM)) beta = rng_ri.normal(1.0, 0.3, N_SIM) mkt = rng_ri.normal(0, 0.012, (1, D_MONTH)) R = beta[:, None] * mkt + rng_ri.normal(0, 1, (N_SIM, D_MONTH)) * sigma[:, None] RV = (sigma[:, None] **2) * rng_ri.chisquare(M_HF, (N_SIM, D_MONTH)) / M_HF# Same firm, same true sigma, DIFFERENT month: no shared sampling noise. R_alt = beta[:, None] * mkt + rng_ri.normal(0, 1, (N_SIM, D_MONTH)) * sigma[:, None]returndict( sigma=sigma, illiq_true=K_HF * sigma / dvol, illiq_classic=np.abs(R).mean(1) / dvol, illiq_realized=K_HF * np.sqrt(RV).mean(1) / dvol, totvol=R.std(1, ddof=1), totvol_disjoint=R_alt.std(1, ddof=1), ivol=(R - beta[:, None] * mkt).std(1, ddof=1), )def rho(a, b):return scipy_stats.spearmanr(a, b).statisticrows_ri = []for label, disp in [("full cross-section", 0.90), ("within size decile", 0.30), ("volume near-constant", 0.10)]: s = simulate_month(disp) rows_ri.append({"volume dispersion": label,"TRUE illiq vs TRUE vol": round(rho(s["illiq_true"], s["sigma"]), 3),"classic vs TOTVOL": round(rho(s["illiq_classic"], s["totvol"]), 3),"classic vs TOTVOL (disjoint)": round(rho(s["illiq_classic"], s["totvol_disjoint"]), 3),"realized vs TOTVOL": round(rho(s["illiq_realized"], s["totvol"]), 3),"fidelity: classic": round(rho(s["illiq_classic"], s["illiq_true"]), 3),"fidelity: realized": round(rho(s["illiq_realized"], s["illiq_true"]), 3), })print("Spearman correlations; true volatility and true volume are INDEPENDENT")print(pd.DataFrame(rows_ri).set_index("volume dispersion").T.to_string())def normal_scores(x):"""Rank-based normal scores, matching the chapter's rank-correlation approach."""return scipy_stats.norm.ppf(scipy_stats.rankdata(x) / (len(x) +1))s = simulate_month(0.30)print("\nPCA composite of (ILLIQ, TOTVOL, IVOL), within size decile:")for name, ill in [("classic ILLIQ", s["illiq_classic"]), ("realized ILLIQ", s["illiq_realized"]), ("TRUE illiquidity", s["illiq_true"])]: X = np.column_stack([normal_scores(c) for c in (ill, s["totvol"], s["ivol"])]) C = np.corrcoef(X, rowvar=False) ev = np.linalg.eigvalsh(C)[::-1]print(f" {name:<17} PC1 share={ev[0] / ev.sum():.3f} "f"corr(ILLIQ,TOTVOL)={C[0, 1]:.3f} corr(ILLIQ,IVOL)={C[0, 2]:.3f}")```Bốn phát hiện, mỗi phát hiện có tác động trực tiếp đến cách đọc các kết quả trong @sec-correlation và @sec-empirical.**Mức thổi phồng cơ học là lớn, và lớn nhất đúng ở nơi chương này làm việc.** Trong một thập phân vị quy mô, tương quan đo được giữa ILLIQ cổ điển và TOTVOL là 0.690 khi cả hai được tính từ lợi nhuận của cùng một tháng, nhưng chỉ là 0.514 khi TOTVOL đến từ một cửa sổ tách rời. Khoảng một phần tư mối liên hệ biểu kiến là do nhiễu lấy mẫu chung tạo ra. Trong trường hợp khối lượng gần như không đổi, khoảng cách còn nới rộng hơn, từ 0.726 lên 0.932. Vì nghiên cứu DIVOP thường xuyên kiểm soát theo quy mô, và quy mô là yếu tố chi phối chính của độ phân tán của giá trị giao dịch, nên chế độ liên quan là chế độ phân tán hẹp, không phải toàn bộ mặt cắt ngang.**Thước đo thực hiện loại bỏ gần như toàn bộ.** Độ trung thực của nó đối với phi thanh khoản thực là 0.999 so với 0.895 của thước đo cổ điển trong một thập phân vị quy mô, và tương quan của nó với TOTVOL (0.609) phản ánh quan hệ thực bị suy giảm chỉ bởi sai số lấy mẫu của chính TOTVOL, không phải bởi bất kỳ thành phần chung nào.**Biến đại diện cổ điển mất lợi thế đúng ở nơi tử số phải gánh vác công việc.** Độ trung thực đối với phi thanh khoản thực giảm từ 0.977 trong toàn bộ mặt cắt ngang xuống 0.862 khi khối lượng gần như không đổi, trong khi thước đo thực hiện duy trì trên 0.998 xuyên suốt. Cách diễn giải là cách đã được dự báo trong @sec-liquidity-amihud-original: trên toàn thị trường, tỷ số cổ điển xếp hạng các cổ phiếu tốt vì *mẫu số* biến thiên rất lớn và được đo không có sai số. Hãy loại bỏ biến thiên đó bằng cách kiểm soát theo quy mô, và phần còn lại là tử số nhiễu.**Chỉ số tổng hợp PCA thừa hưởng sự nhiễm bẩn, dù ở mức khiêm tốn.** Dùng biến đại diện cổ điển, tương quan ILLIQ-TOTVOL đi vào PCA là 0.713 so với giá trị thực 0.629, và tỷ lệ phương sai của thành phần thứ nhất là 0.841 so với giá trị thực 0.829. Thay bằng thước đo thực hiện thì tái tạo gần như chính xác ma trận tương quan thực và tỷ lệ PC1 thực (0.628 và 0.829). Do đó chỉ số tổng hợp bị phóng đại nhẹ khi dùng làm bản tóm tắt biến thiên chung: nó một phần đang tóm tắt sai số đo lường chung thay vì một nhân tố phân kỳ quan điểm chung. Sự méo mó ở đây nhỏ vì chỉ một trong ba đầu vào được thay thế; một chỉ số tổng hợp được xây hoàn toàn từ các thống kê hằng ngày cùng cửa sổ sẽ tệ hơn.### Điều này có ý nghĩa gì đối với các kết quả của chươngCác cách đọc thực tiễn là hẹp và đáng được nêu chính xác, vì các hiệu ứng trên là có thật nhưng không quá lớn.1. **Các tương quan được báo cáo giữa các biến đại diện dựa trên lợi nhuận là cận trên.** Ở bất cứ nơi nào @sec-correlation cho thấy ILLIQ tương quan với TOTVOL, IVOL hoặc BASPREAD kiểu cao–thấp, một phần của tương quan đó là do cách xây dựng chứ không phải kinh tế. Các tương quan với biến đại diện được xây từ dữ liệu *khác* (DTO và SUV từ vòng quay, DISP từ dự báo của nhà phân tích) không bị ảnh hưởng bởi kênh này và có thể được hiểu theo đúng giá trị báo cáo.2. **Một kiểm tra độ vững rẻ tiền không cần dữ liệu trong ngày nào.** Tính lại ma trận tương quan với các biến đại diện biến động được ước lượng trên một cửa sổ liền kề, không chồng lấn sẽ phá vỡ trực tiếp kênh nhiễu chung. Bất kỳ tương quan nào còn tồn tại không phải là sản phẩm phụ của sai số lấy mẫu chung. Đây là cột `disjoint` của mô phỏng, được triển khai trên dữ liệu thực, và chỉ tốn thêm một lệnh `shift`.3. **Đừng diễn giải quá mức tỷ lệ phương sai của PC1.** Nó bị chệch lên do nhiễu chung, nên nhận định rằng một nhân tố duy nhất giải thích phần lớn biến thiên chung của các biến đại diện DIVOP có phần yếu hơn so với những gì các trị riêng thô gợi ý.4. **Kiểm soát theo quy mô làm vấn đề trở nên hệ trọng hơn.** Bất kỳ đặc tả nào hoạt động trong các nhóm quy mô đều loại bỏ biến thiên khối lượng vốn mang phần lớn tín hiệu mặt cắt ngang của ILLIQ cổ điển, để lại một biến đại diện có độ trung thực đối với phi thanh khoản thực giảm xuống còn khoảng 0.86. Đây là nơi việc thay bằng @eq-divop-realized-illiq mang lại nhiều nhất.### Xây dựngBiến đại diện thực hiện là một thay thế trực tiếp cho `amihud_daily` trong `compute_spread_and_illiq()`. Nó đòi hỏi các đầu vào trong ngày có tính đến phiên giao dịch được mô tả trong @sec-micro-realized-illiq.```{python}#| label: realized-illiq-divop#| eval: false#| code-summary: "Construct realized ILLIQ as a DIVOP proxy"def compute_realized_illiq(realized_daily, config, min_active=20):""" Monthly realized Amihud from a symbol-day intraday panel with columns [ticker, date, rv, bv, n_active, dvol_continuous]. `min_active` screens out days whose five-minute grid is mostly stale prices; below roughly 20 active intervals of 45 the estimator's precision advantage largely disappears (see the microstructure chapter). """ k = np.sqrt(2/ np.pi) df = realized_daily.copy() n_before =len(df) df = df[(df["n_active"] >= min_active) & (df["dvol_continuous"] >0)]print(f"Thin-trading screen: kept {len(df):,} of {n_before:,} symbol-days "f"({100*len(df) /max(n_before, 1):.1f}%)") dvol_bn = df["dvol_continuous"] /1e9 df["rilliq_daily"] = k * np.sqrt(df["rv"]) / dvol_bn df["rilliq_bv_daily"] = k * np.sqrt(df["bv"].clip(lower=0)) / dvol_bn df["ym"] = df["date"].dt.to_period("M") agg = (df.groupby(["ticker", "ym"]) .agg(rilliq_mean=("rilliq_daily", "mean"), rilliq_bv_mean=("rilliq_bv_daily", "mean"), n_days=("rilliq_daily", "size")) .reset_index()) agg = agg[agg["n_days"] >= config.get("min_days_per_month", 15)].copy() agg["log_rilliq"] = np.log(agg["rilliq_mean"] +1e-10)return aggdef totvol_disjoint(monthly_vol):""" Robustness control requiring no intraday data: pair each month's ILLIQ with the PREVIOUS month's volatility, so the two share no daily returns. """ out = monthly_vol.sort_values(["ticker", "ym"]).copy() out["totvol_lag"] = out.groupby("ticker")["totvol"].shift(1)return out```### Những lưu ý riêng của Việt Nam1. **Độ phủ là ràng buộc then chốt.** Dữ liệu trong ngày thực tế chỉ có cho phần thanh khoản cao của HOSE, khoảng VN30 và các doanh nghiệp vốn hóa vừa có quy mô lớn hơn. Vì bước sàng lọc loại các doanh nghiệp một cách không ngẫu nhiên đúng theo chiều đang nghiên cứu, một phân tích DIVOP giới hạn ở mẫu còn lại sẽ bị điều kiện hóa theo thanh khoản. Hãy báo cáo tỷ lệ được giữ lại.2. **Dùng biến thể bipower.** Biên độ giá hằng ngày của Việt Nam khiến các biến động rời rạc lớn trở nên thường lệ, và một cú nhảy thông tin làm phồng phương sai thực hiện trong khi để biến thiên bipower gần như không chệch (@sec-liquidity-realized). Với một chương về sự phân kỳ quan điểm, điều này quan trọng hơn thường lệ, vì những ngày có nhiều bất đồng nhất cũng là những ngày dễ chạm biên độ nhất.3. **Kiểm tra cửa sổ tách rời nên được chạy trong mọi trường hợp.** Nó không đòi hỏi dữ liệu nào mà chương này chưa có, nó xử lý trực tiếp sự nhiễm bẩn đã nêu ở trên, và nó áp dụng cho toàn bộ mẫu chứ không chỉ tập con thanh khoản cao.4. **Mẫu số không đổi.** @eq-divop-realized-illiq chỉ cải thiện tử số; các phức tạp về giao dịch thỏa thuận và báo cáo ảnh hưởng đến DolVol, được thảo luận trong chương vi cấu trúc thị trường, áp dụng như nhau cho cả hai phiên bản.# Phân tán dự báo của nhà phân tích {#sec-analyst}## Động cơ lý thuyếtPhân tán dự báo của nhà phân tích, tức độ lệch chuẩn mặt cắt ngang của các dự báo lợi nhuận của từng nhà phân tích, là thước đo trực tiếp nhất của sự phân kỳ quan điểm. Khác với các biến đại diện dựa trên thị trường nắm bắt sự bất đồng một cách gián tiếp, phân tán dự báo đo trực tiếp sự bất đồng giữa các thành viên thị trường có thông tin. @abarbanell1995analysts thiết lập cơ sở lý thuyết, và @diether2002differences chứng minh rằng các cổ phiếu có phân tán dự báo của nhà phân tích cao hơn có lợi nhuận về sau thấp hơn, phù hợp với giả thuyết định giá quá cao của Miller.## Thách thức dữ liệu ở Việt NamViệc xây dựng phân tán dự báo của nhà phân tích ở Việt Nam đặt ra những thách thức đáng kể so với Hoa Kỳ:- **Độ rộng của độ phủ.** Trong khi I/B/E/S phủ hơn 4,000 doanh nghiệp Hoa Kỳ, chỉ có 100--150 doanh nghiệp Việt Nam thường được ít nhất 3 nhà phân tích theo dõi, tập trung ở các cổ phiếu thành phần VN30.- **Nguồn dữ liệu.** Dự báo của nhà phân tích có sẵn từ DataCore.vn, FiinPro, Bloomberg và Refinitiv. Việc chọn nguồn ảnh hưởng đến độ phủ và tính kịp thời.- **Dự báo lỗi thời.** Với độ phủ hạn chế, các dự báo có thể không được sửa đổi trong nhiều tháng. Theo phương pháp I/B/E/S, chúng ta duy trì hiệu lực của mỗi dự báo tối đa 105 ngày.## Phương pháp xây dựngQuá trình xây dựng diễn ra như sau:1. **Làm sạch các dự báo riêng lẻ.** Loại bỏ các quan sát mà ngày công bố đi trước ngày rà soát. Chỉ giữ lại các dự báo EPS hằng năm. Với mỗi cặp nhà phân tích-mã cổ phiếu-kỳ tài chính, chỉ giữ lại dự báo mới nhất trong mỗi tháng dương lịch.2. **Xử lý các ước lượng bị ngừng và bị loại.** Loại bỏ các dự báo mà nhà phân tích đã rời công ty môi giới hoặc ước lượng đã bị loại khỏi đồng thuận.3. **Duy trì hiệu lực dự báo có kiểm soát độ lỗi thời.** Mỗi dự báo có hiệu lực cho đến thời điểm sớm hơn trong số: (a) dự báo kế tiếp của cùng nhà phân tích, (b) 105 ngày sau ngày công bố, hoặc (c) ngày công bố lợi nhuận thực tế.4. **Mở rộng sang tần suất hằng tháng.** Với mỗi cặp mã cổ phiếu-tháng, xác định mọi dự báo còn hiệu lực và tính độ phân tán.5. **Tính các thước đo đã chuẩn hóa tỷ lệ:**$$\text{DISP1}_{i,m} = \frac{\text{Std}(\hat{\text{EPS}}_{i,m}^{(a)})}{|\text{Mean}(\hat{\text{EPS}}_{i,m}^{(a)})|}\qquad\text{DISP2}_{i,m} = \frac{\text{Std}(\hat{\text{EPS}}_{i,m}^{(a)})}{\bar{P}_{i,m}}$$```{python}#| label: analyst-dispersion#| code-summary: "Construct analyst forecast dispersion (DISP1, DISP2)"def construct_analyst_dispersion(forecasts_df, price_df, config):""" Construct analyst forecast dispersion measures. Parameters ---------- forecasts_df : pd.DataFrame Individual analyst forecasts with: ticker, analyst_id, broker, fpedats, anndats, revdats, value (EPS), anndats_act. price_df : pd.DataFrame Monthly price: ticker, month, mean_price. config : dict With min_analysts, forecast_carry_days. """ carry_days = config['forecast_carry_days'] min_analysts = config['min_analysts'] df = forecasts_df.copy() df = df[df['anndats'] <= df['revdats']].copy() df = df.dropna(subset=['fpedats', 'anndats', 'value'])# Latest forecast per analyst-month df['ym'] = df['anndats'].dt.to_period('M') df = df.sort_values( ['ticker', 'fpedats', 'analyst_id', 'ym', 'anndats', 'revdats'] ) df = df.groupby(['ticker', 'fpedats', 'analyst_id', 'ym']).tail(1)# Carry-forward end date df = df.sort_values( ['ticker', 'analyst_id', 'fpedats', 'anndats'], ascending=[True, True, True, False] ) df['next_ann'] = df.groupby( ['ticker', 'analyst_id', 'fpedats'] )['anndats'].shift(-1)def _carry_end(row): candidates = [row['anndats'] + pd.Timedelta(days=carry_days)]if pd.notna(row.get('next_ann')): candidates.append(row['next_ann'])if pd.notna(row.get('anndats_act')): candidates.append(row['anndats_act'])returnmin(candidates) df['carry_end'] = df.apply(_carry_end, axis=1)# Monthly expansion months = pd.period_range(config['beg_date'], config['end_date'], freq='M') records = []for month in months: me = month.to_timestamp(how='end') valid = df[(df['anndats'] <= me) & (df['carry_end'] > me)].copy() valid = valid[valid['fpedats'] > me] valid = valid.sort_values(['ticker', 'analyst_id', 'anndats']) valid = valid.groupby(['ticker', 'analyst_id']).tail(1) disp = valid.groupby('ticker').agg( n_analysts=('analyst_id', 'nunique'), mean_fcst=('value', 'mean'), std_fcst=('value', 'std'), ).reset_index() disp['month'] = month records.append(disp)ifnot records:return pd.DataFrame() disp_df = pd.concat(records, ignore_index=True)# Scaled measures disp_df['disp1'] = np.where( disp_df['mean_fcst'].abs() >0, disp_df['std_fcst'] / disp_df['mean_fcst'].abs(), np.nan ) disp_df = disp_df.merge(price_df, on=['ticker', 'month'], how='left') disp_df['disp2'] = np.where( disp_df['mean_price'] >0, disp_df['std_fcst'] / disp_df['mean_price'], np.nan ) disp_df['disp_raw'] = disp_df['std_fcst'] out = disp_df[disp_df['n_analysts'] >= min_analysts].copy()print(f"DISP: {len(out):,} ticker-months (>= {min_analysts} analysts)")print(f" Mean analysts: {out['n_analysts'].mean():.1f}")return out```## Các lưu ý về chuẩn hóa tỷ lệTheo @cheong2011eps, chúng ta lưu ý rằng mỗi cách chọn chuẩn hóa tỷ lệ đều có điểm yếu. DISP1 (chuẩn hóa theo giá trị tuyệt đối của dự báo trung bình) có thể cho giá trị cực đoan khi dự báo trung bình tiến về không, điều phổ biến với các doanh nghiệp Việt Nam gần điểm hòa vốn. DISP2 (chuẩn hóa theo giá) đưa vào một tương quan âm cơ học giữa giá và độ phân tán đã chuẩn hóa. Chúng tôi khuyến nghị báo cáo cả ba phiên bản (DISP1, DISP2 và DISP_RAW không chuẩn hóa với $\ln(\text{Price})$ làm biến kiểm soát bổ sung), và winsorize DISP1 ở phân vị thứ 1 và thứ 99.::: callout-warning## Lưu ý về phân tán của nhà phân tích ở các thị trường có độ phủ mỏngVới độ phủ điển hình 5--10 nhà phân tích mỗi doanh nghiệp ở Việt Nam (so với 15--25 ở Hoa Kỳ), phân tán dự báo được ước lượng với nhiễu lớn hơn đáng kể. Một thước đo phân tán từ 3 nhà phân tích có phân phối mẫu rất khác so với thước đo từ 20 nhà phân tích. Hãy luôn đưa số nhà phân tích vào làm biến kiểm soát và kiểm tra độ vững với các ngưỡng tối thiểu số nhà phân tích khác nhau (3, 5, 7).:::# Tương quan mặt cắt ngang giữa các biến đại diện DIVOP {#sec-correlation}Một câu hỏi thực nghiệm quan trọng là mức độ mà các biến đại diện DIVOP khác nhau nắm bắt cùng một cấu trúc tiềm ẩn. Nếu sự phân kỳ quan điểm là một biến tiềm ẩn được xác định rõ, chúng ta kỳ vọng có các tương quan dương giữa mọi biến đại diện, dù các tương quan không nhất thiết phải cao vì mỗi biến nắm bắt một khía cạnh khác nhau của sự bất đồng.```{python}#| label: correlation-analysis#| code-summary: "Spearman rank correlations among DIVOP proxies"def compute_divop_correlations(merged_df, proxies=None):""" Compute and visualize Spearman correlations among DIVOP proxies. We use rank correlations because many proxies are right-skewed. """if proxies isNone: proxies = ['dto', 'suv', 'total_volatility', 'idio_volatility','baspread', 'amihud_daily', 'disp1', 'disp2' ] available = [p for p in proxies if p in merged_df.columns] data = merged_df[available].dropna() n =len(available) rho_mat = np.eye(n) p_mat = np.zeros((n, n))for i inrange(n):for j inrange(i +1, n): rho, p = scipy_stats.spearmanr( data[available[i]], data[available[j]] ) rho_mat[i, j] = rho_mat[j, i] = rho p_mat[i, j] = p_mat[j, i] = p labels = {'dto': 'DTO', 'suv': 'SUV','total_volatility': 'VOL', 'idio_volatility': 'IVOL','baspread': 'SPREAD', 'amihud_daily': 'ILLIQ','disp1': 'DISP1', 'disp2': 'DISP2'} pretty = [labels.get(c, c) for c in available] corr_df = pd.DataFrame(rho_mat, index=pretty, columns=pretty)# Heatmap fig, ax = plt.subplots(figsize=(9, 7)) mask = np.triu(np.ones_like(corr_df, dtype=bool), k=1) sns.heatmap( corr_df, mask=mask, annot=True, fmt='.3f', cmap='RdBu_r', center=0, vmin=-0.4, vmax=0.7, square=True, linewidths=0.5, cbar_kws={'shrink': 0.8, 'label': 'Spearman ρ'}, ax=ax ) ax.set_title('Spearman Correlations Among DIVOP Proxies\n''Vietnamese Equity Market', fontsize=13, fontweight='bold') plt.tight_layout() plt.savefig('divop_correlations.png', dpi=300, bbox_inches='tight') plt.show()return corr_df```### Các mô thức tương quan kỳ vọngDựa trên bằng chứng và lý thuyết ở Hoa Kỳ, chúng ta kỳ vọng:| Cặp | Kỳ vọng | Cơ sở ||:-----------------------|:-----------------------|:-----------------------|| DTO × SUV | Dương cao | Cả hai nắm bắt khối lượng bất thường; SUV tinh chỉnh DTO || VOL × IVOL | Dương cao | IVOL là tập con của biến động tổng || SPREAD × ILLIQ | Dương trung bình-cao | Cả hai nắm bắt bất cân xứng thông tin || Khối lượng × Biến động | Dương trung bình | @shalen1993volume liên kết cả hai với mức phân tán niềm tin || Nhà phân tích × Dựa trên thị trường | Dương yếu-trung bình | Các nhóm nhà đầu tư khác nhau |: Cấu trúc tương quan kỳ vọng giữa các biến đại diện DIVOP {#tbl-expected-corr}# Thống kê mô tả và các tính chất mặt cắt ngang {#sec-empirical}## Thống kê tóm tắt```{python}#| label: descriptive-stats#| code-summary: "Descriptive statistics for all DIVOP proxies"def descriptive_statistics(merged_df):"""Comprehensive descriptive statistics for DIVOP proxies.""" proxies = {'dto': 'Unexplained Volume (DTO)','suv': 'Std Unexplained Volume (SUV)','total_volatility': 'Total Return Volatility','idio_volatility': 'Idiosyncratic Volatility','baspread': 'Bid-Ask Spread','amihud_daily': 'Amihud Illiquidity','disp1': 'Analyst Disp (mean-scaled)','disp2': 'Analyst Disp (price-scaled)', } avail = {k: v for k, v in proxies.items() if k in merged_df.columns} rows = []for col, label in avail.items(): s = merged_df[col].dropna() rows.append({'Proxy': label, 'N': f'{len(s):,}','Mean': f'{s.mean():.6f}', 'Std': f'{s.std():.6f}','P5': f'{s.quantile(.05):.6f}','Median': f'{s.median():.6f}','P95': f'{s.quantile(.95):.6f}','Skew': f'{s.skew():.2f}','Kurt': f'{s.kurtosis():.2f}', }) stats = pd.DataFrame(rows).set_index('Proxy')print("\n"+"="*90)print("Descriptive Statistics of DIVOP Proxies")print("Vietnamese Equity Market, HOSE and HNX")print("="*90)print(stats.to_string())return stats```## DIVOP theo đặc điểm doanh nghiệp```{python}#| label: by-characteristics#| code-summary: "DIVOP by size, exchange, and foreign ownership"def divop_by_size(merged_df):"""Mean DIVOP proxies by market-cap quintile.""" df = merged_df.copy() df['mkt_cap'] = df['close'] * df['shares_outstanding'] df['size_q'] = df.groupby('date')['mkt_cap'].transform(lambda x: pd.qcut(x, 5, labels=['Q1 Small','Q2','Q3','Q4','Q5 Large'], duplicates='drop') ) proxies = ['dto','suv','total_volatility','idio_volatility','baspread','amihud_daily'] avail = [p for p in proxies if p in df.columns] tab = df.groupby('size_q')[avail].mean()print("\n=== Mean DIVOP by Size Quintile ===")print(tab.to_string(float_format='{:.6f}'.format))return tabdef divop_by_exchange(merged_df):"""Compare mean DIVOP across HOSE and HNX.""" proxies = ['dto','suv','total_volatility','idio_volatility','baspread','amihud_daily'] avail = [p for p in proxies if p in merged_df.columns] tab = merged_df.groupby('exchange')[avail].mean()print("\n=== Mean DIVOP by Exchange ===")print(tab.to_string(float_format='{:.6f}'.format))return tab```## Diễn biến theo chuỗi thời gian```{python}#| label: time-series-plot#| code-summary: "Time-series evolution of DIVOP proxies"def plot_divop_timeseries(merged_df):"""Plot monthly cross-sectional median DIVOP with crisis shading.""" df = merged_df.copy() df['ym'] = df['date'].dt.to_period('M') proxies = ['dto','suv','total_volatility','baspread'] avail = [p for p in proxies if p in df.columns] monthly = df.groupby('ym')[avail].median() monthly.index = monthly.index.to_timestamp() fig, axes = plt.subplots(len(avail), 1, figsize=(13, 3.5*len(avail)), sharex=True)iflen(avail) ==1: axes = [axes] labels = {'dto':'DTO','suv':'SUV','total_volatility':'Volatility','baspread':'Spread'} colors = ['#1976D2','#388E3C','#F57C00','#D32F2F']for i, (proxy, ax) inenumerate(zip(avail, axes)): ax.plot(monthly.index, monthly[proxy], color=colors[i], linewidth=1.3) ax.set_ylabel(labels.get(proxy, proxy), fontsize=10) ax.grid(True, alpha=0.25)for s, e, c in [('2008-01','2009-06','red'), ('2020-01','2020-12','orange'), ('2022-09','2023-06','purple')]: ax.axvspan(pd.Timestamp(s), pd.Timestamp(e), alpha=0.1, color=c) axes[0].set_title('Time-Series of DIVOP Proxies\n''Monthly Cross-Sectional Median, HOSE & HNX', fontsize=13, fontweight='bold')from matplotlib.patches import Patch axes[-1].legend(handles=[ Patch(facecolor='red', alpha=.2, label='GFC 2008-09'), Patch(facecolor='orange', alpha=.2, label='COVID-19'), Patch(facecolor='purple', alpha=.2, label='Bond Crisis 2022-23'), ], loc='upper right', fontsize=8) plt.tight_layout() plt.savefig('divop_timeseries.png', dpi=300, bbox_inches='tight') plt.show()```# Tổng hợp lại {#sec-pipeline}```{python}#| label: merge-all#| code-summary: "Master pipeline: build full DIVOP dataset"def build_divop_dataset(config):""" Master pipeline: load data, construct all DIVOP proxies, merge into a single stock-date panel. """ df = load_daily_data(config) df = apply_sample_filters(df, config) df = adjust_for_corporate_actions(df) calendar = build_trading_calendar(df, config) df = compute_dto(df, config) suv_df = compute_suv(df, calendar, config) vol_df = compute_volatility(df, calendar, config) df = compute_spread_and_illiq(df, config)# Merge base = df[['ticker','date','ret','close','volume','shares_outstanding','exchange','industry_icb','foreign_ownership_pct','turnover','mato','dto','baspread','amihud_daily','limit_hit']].copy()ifnot suv_df.empty: base = base.merge( suv_df[['ticker','date','suv','predicted_turnover']], on=['ticker','date'], how='left')ifnot vol_df.empty: base = base.merge( vol_df[['ticker','date','total_volatility','idio_volatility','market_beta']], on=['ticker','date'], how='left')print(f"\n=== Final DIVOP Dataset ===")print(f"Shape: {base.shape}")print(f"Tickers: {base['ticker'].nunique()}")return base```# Các ứng dụng thực nghiệm {#sec-applications}## Ứng dụng 1: DIVOP và mặt cắt ngang của lợi nhuậnPhép kiểm định cơ bản của giả thuyết Miller là liệu các cổ phiếu có sự phân kỳ quan điểm cao hơn có lợi nhuận về sau thấp hơn hay không. Chúng ta triển khai các hồi quy mặt cắt ngang Fama-MacBeth:$$r_{i,t+1:t+h} = \gamma_{0,t} + \gamma_{1,t} \cdot \text{DIVOP}_{i,t} + \gamma_{2,t}' \mathbf{X}_{i,t} + \varepsilon_{i,t}$$trong đó $\mathbf{X}_{i,t}$ gồm các biến kiểm soát là beta thị trường, logarit vốn hóa thị trường và logarit tỷ số giá trị sổ sách trên giá trị thị trường. Giả thuyết Miller dự đoán $\bar{\gamma}_1 < 0$.```{python}#| label: fama-macbeth#| code-summary: "Fama-MacBeth regressions of returns on DIVOP"def fama_macbeth_divop(merged_df, divop_proxy='suv', controls=None, horizon=21):""" Fama-MacBeth cross-sectional regressions. Miller predicts gamma_1 < 0; Varian predicts gamma_1 > 0. """if controls isNone: controls = ['market_beta', 'log_mktcap'] df = merged_df.copy() df = df.sort_values(['ticker', 'date']) df['fwd_ret'] = df.groupby('ticker')['ret'].transform(lambda x: x.shift(-1).rolling(horizon).sum().shift(-(horizon-1)) ) df['log_mktcap'] = np.log( df['close'] * df['shares_outstanding'] +1 ) reg_vars = ['fwd_ret', divop_proxy] +\ [c for c in controls if c in df.columns] df_reg = df[['ticker','date'] + reg_vars].dropna()from numpy.linalg import lstsq results = []for date, cross in df_reg.groupby('date'):iflen(cross) <30: continue y = cross['fwd_ret'].values X_cols = [divop_proxy] + [c for c in controls if c in cross.columns] X = np.column_stack([np.ones(len(cross)), cross[X_cols].values])try: coefs, _, _, _ = lstsq(X, y, rcond=None) results.append({'date': date, 'intercept': coefs[0],f'gamma_{divop_proxy}': coefs[1], 'n': len(cross), })exceptException: continue fm = pd.DataFrame(results) gc =f'gamma_{divop_proxy}' mu = fm[gc].mean() se = fm[gc].std() / np.sqrt(len(fm)) t = mu / seprint(f"\n=== Fama-MacBeth: {divop_proxy} -> "f"{horizon}-day fwd returns ===")print(f" Mean gamma: {mu:.6f}, t-stat: {t:.3f}")if t <-1.96: print(" -> Supports Miller (1977)")elif t >1.96: print(" -> Supports Varian (1985)")else: print(" -> Inconclusive at 5%")return fm```## Ứng dụng 2: DIVOP và công bố lợi nhuậnTheo @berkman2009sell, chúng ta kiểm định liệu các cổ phiếu có DIVOP cao có lợi nhuận bất thường âm quanh các đợt công bố lợi nhuận hay không, vì việc giải tỏa bất định làm giảm phần bù lạc quan.```{python}#| label: ea-event#| code-summary: "Event study: DIVOP and earnings announcement returns"def divop_earnings_event(merged_df, ea_dates_df, divop_proxy='suv', window=(-1, 3)):""" Sort stocks into DIVOP quintiles pre-EA, compute CAR in window. Miller predicts: Q5 (high DIVOP) has lower CAR than Q1 (low DIVOP). """ df = merged_df.copy() ea = ea_dates_df.copy()# Pre-EA DIVOP value (5 days before) ea['pre_date'] = ea['ea_date'] - pd.Timedelta(days=5) ea = ea.merge( df[['ticker','date',divop_proxy]].rename( columns={'date':'pre_date'}), on=['ticker','pre_date'], how='inner' ) ea['divop_q'] = pd.qcut( ea[divop_proxy], 5, labels=['Q1 Low','Q2','Q3','Q4','Q5 High'], duplicates='drop' )print(f"\n=== EA Event Study by {divop_proxy} quintile ===")print(f" Window: ({window[0]}, {window[1]}) days")print(f" Miller predicts: Q5 has lower CAR than Q1")return ea```## Ứng dụng 3: Chỉ số DIVOP tổng hợp bằng PCAKhi cần một thước đo tóm tắt duy nhất về sự bất đồng, PCA trên bộ các biến đại diện đã chuẩn hóa sẽ trích ra "nhân tố bất đồng" chung.```{python}#| label: pca-composite#| code-summary: "Composite DIVOP index via PCA"from sklearn.preprocessing import StandardScalerfrom sklearn.decomposition import PCAdef composite_divop_pca(merged_df, proxies=None):"""Extract first principal component from standardized DIVOP proxies."""if proxies isNone: proxies = ['dto','suv','total_volatility','idio_volatility','baspread','amihud_daily'] avail = [p for p in proxies if p in merged_df.columns] data = merged_df[['ticker','date'] + avail].dropna() scaler = StandardScaler() X = scaler.fit_transform(data[avail]) pca = PCA(n_components=3) factors = pca.fit_transform(X) data['divop_composite'] = factors[:, 0]# Ensure positive correlation with inputsfor col in avail:if data['divop_composite'].corr(data[col]) <0: data['divop_composite'] *=-1break loadings = pd.DataFrame( pca.components_.T, index=avail, columns=['PC1','PC2','PC3'] )print(f"\n=== PCA Composite DIVOP ===")print(f"Variance explained: "f"{pca.explained_variance_ratio_[:3].round(3)}")print(f"\nLoadings:\n{loadings.to_string(float_format='{:.4f}'.format)}")return data[['ticker','date','divop_composite']], loadings```# Kết luận và khuyến nghị thực tiễnChương này đã trình bày một phương pháp toàn diện để xây dựng bảy biến đại diện riêng biệt cho sự phân kỳ quan điểm của nhà đầu tư, được điều chỉnh cho thị trường chứng khoán Việt Nam. Chúng tôi kết thúc bằng các khuyến nghị thực tiễn:**1. Ưu tiên nhiều biến đại diện.** Không có thước đo DIVOP đơn lẻ nào không có hạn chế. Chúng tôi khuyến nghị xây dựng và báo cáo kết quả cho ít nhất ba biến đại diện trải trên các kênh kinh tế khác nhau (khối lượng, biến động, chênh lệch giá hoặc dựa trên nhà phân tích).**2. Tính đến vi cấu trúc riêng của Việt Nam.** Biên độ giá hằng ngày, thanh toán T+2, các ràng buộc sở hữu nước ngoài và cấu trúc thị trường dẫn dắt bởi lệnh đều ảnh hưởng đến các tính chất của DIVOP. Hãy đánh dấu các ngày chạm biên độ, đưa vào hiệu ứng cố định theo sàn, và kiểm soát sở hữu nước ngoài.**3. Việt Nam như một phòng thí nghiệm tự nhiên cho Miller (1977).** Việc không có bán khống đến hết năm 2024 và sự áp đảo của nhà đầu tư cá nhân tạo ra những điều kiện khớp sát với bối cảnh lý thuyết của Miller. Việc đưa vào bán khống năm 2025 tạo ra một thử nghiệm tự nhiên để xem xét việc nới lỏng các hạn chế bán khống ảnh hưởng thế nào đến quan hệ DIVOP-lợi nhuận.**4. Kiểm soát độ phủ nhà phân tích khi dùng các thước đo DISP.** Với độ phủ điển hình 5--10 nhà phân tích mỗi doanh nghiệp, phân tán dự báo được ước lượng với nhiễu lớn hơn so với các thị trường phát triển. Hãy luôn đưa số nhà phân tích vào làm biến kiểm soát và thực hiện các kiểm tra độ vững với các ngưỡng tối thiểu số nhà phân tích khác nhau.**5. Cân nhắc xây dựng chỉ số tổng hợp.** Khi các nhà nghiên cứu cần một thước đo tóm tắt duy nhất về sự bất đồng, chỉ số tổng hợp dựa trên PCA được mô tả trong @sec-applications cung cấp một cách tiếp cận có nguyên tắc để tổng hợp thông tin qua các biến đại diện riêng lẻ. Thành phần chính thứ nhất thường giải thích 30-50% biến thiên chung trong bộ các thước đo DIVOP.**6. Winsorize mạnh tay.** Một số biến đại diện DIVOP (đặc biệt là DISP1, ILLIQ Amihud và SUV) có các giá trị ngoại lai cực đoan trong dữ liệu Việt Nam. Winsorization ở phân vị thứ 1 và thứ 99 (hoặc thậm chí thứ 2 và thứ 98 đối với DISP1) là thiết yếu để thu được kết quả hồi quy đáng tin cậy.**7. Thận trọng với suy luận nhân quả.** Các biến đại diện DIVOP là nội sinh, chúng phản ứng với cùng những đặc điểm doanh nghiệp (quy mô, đòn bẩy, tăng trưởng) vốn cũng ảnh hưởng đến lợi nhuận. Các nhà nghiên cứu nên dùng các biến kiểm soát phù hợp, cân nhắc biến công cụ khi khả thi, và nêu rõ các hạn chế của chiến lược nhận diện của mình.Khung DIVOP đặc biệt phù hợp với thị trường Việt Nam ở giai đoạn phát triển hiện nay. Khi thị trường trưởng thành hướng tới khả năng được nâng hạng lên nhóm Thị trường mới nổi của FTSE, khi bán khống trở nên phổ biến hơn, và khi sự tham gia của nhà đầu tư tổ chức tăng lên, động lực của sự phân kỳ quan điểm và các hàm ý định giá của nó nhiều khả năng sẽ thay đổi đáng kể. Phương pháp được trình bày trong chương này trang bị cho các nhà nghiên cứu những công cụ để ghi nhận và phân tích các thay đổi đó khi chúng diễn ra.