import pandas as pdimport numpy as npimport matplotlib.pyplot as pltimport matplotlib.ticker as mtickerimport statsmodels.api as smimport statsmodels.formula.api as smffrom scipy import statsfrom typing import Optionalimport warningswarnings.filterwarnings("ignore")plt.rcParams.update({"figure.dpi": 150,"axes.spines.top": False,"axes.spines.right": False,"font.size": 11,})
Quản trị lợi nhuận là việc các nhà quản lý can thiệp có chủ đích vào quá trình lập báo cáo tài chính nhằm đạt được những kết quả phục vụ mục tiêu riêng, dù là để đạt dự báo của các nhà phân tích, kích hoạt ngưỡng thưởng, tránh vi phạm điều khoản vay nợ, hay tác động đến định giá cổ phiếu. Tuy khái niệm này khá trực quan, việc phát hiện nó một cách chặt chẽ lại là một trong những thách thức phương pháp luận lâu đời nhất của nghiên cứu kế toán thực nghiệm.
Khó khăn này mang tính căn bản: nhà nghiên cứu chỉ quan sát được các khoản dồn tích tổng cộng, vốn gồm một thành phần hợp lý (phản ánh hoạt động kinh tế thực) và một thành phần tùy ý (phản ánh sự can thiệp của nhà quản lý). Tách hai thành phần này đòi hỏi một mô hình về mức dồn tích mà lẽ ra phải có nếu không có thao túng, mà tài liệu nghiên cứu gọi là các khoản dồn tích không tùy ý (NDA). Phần dư bất kỳ, tức khoảng chênh giữa các khoản dồn tích quan sát được và dự báo của mô hình, sau đó được quy cho sự tùy ý của nhà quản lý. Do đó, chất lượng của phương pháp phát hiện phụ thuộc hoàn toàn vào chất lượng của mô hình này.
Chương này xem xét ba cách tiếp cận nền tảng để đo lường quản trị lợi nhuận (tức là mô hình Healy (1985), mô hình Jones (1991) và mô hình Jones điều chỉnh của Dechow, Sloan, và Sweeney (1995)) và đánh giá các tính chất thống kê của chúng bằng mô phỏng. Sau đó, chúng ta điều chỉnh phân tích cho bối cảnh thể chế của Việt Nam, nơi cơ cấu quản trị, chuẩn mực kế toán và chế độ thực thi khác biệt tạo ra cả những động cơ quản trị lợi nhuận đặc thù lẫn những thách thức đặc thù trong việc phát hiện nó.
27.0.1 Định nghĩa quản trị lợi nhuận
Một cách phân loại hữu ích phân biệt ba hình thức:
Quản trị lợi nhuận dựa trên dồn tích (AEM). Nhà quản lý tận dụng quyền tùy ý trong khuôn khổ chuẩn mực kế toán để dịch chuyển thời điểm ghi nhận doanh thu hoặc chi phí. Ví dụ gồm ghi nhận doanh thu quá tích cực, trì hoãn việc ghi giảm giá trị tài sản, hoặc thao túng các ước tính dự phòng. Hình thức này không làm thay đổi dòng tiền cơ bản của doanh nghiệp.
Quản trị lợi nhuận thực (REM). Nhà quản lý thực hiện các hành động kinh tế thực sự (ví dụ: sản xuất vượt mức để giảm chi phí đơn vị, cắt giảm chi phí R&D hoặc quảng cáo, giảm giá bán để đẩy nhanh doanh số) có hệ quả thực đối với dòng tiền (Roychowdhury 2006). Những hành động này có thể cải thiện lợi nhuận kỳ hiện tại với cái giá là giá trị tương lai.
Dịch chuyển phân loại (classification shifting). Nhà quản lý phân loại lại các khoản chi phí cốt lõi thành các khoản không thường xuyên để thổi phồng lợi nhuận cốt lõi mà không làm thay đổi lợi nhuận ròng cuối cùng. Hình thức này giữ nguyên cả tổng dồn tích lẫn dòng tiền.
27.0.2 Vì sao là Việt Nam?
Môi trường thể chế của Việt Nam khuếch đại một số kênh liên quan đến nghiên cứu quản trị lợi nhuận:
Động cơ của doanh nghiệp nhà nước (DNNN). Các DNNN được cổ phần hóa một phần chịu hai áp lực: chỉ tiêu chính trị từ cổ đông nhà nước và kỳ vọng thị trường từ các nhà đầu tư thiểu số.
Thực thi pháp luật. Ủy ban Chứng khoán Nhà nước (SSC) của Việt Nam có nguồn lực hạn chế và lịch sử thể chế ngắn so với các cơ quan như SEC của Hoa Kỳ. Thực thi yếu làm giảm chi phí kỳ vọng của việc thao túng, có thể làm tăng mức độ phổ biến của nó (Leuz, Nanda, và Wysocki 2003).
Chuẩn mực kế toán. VAS (Chuẩn mực Kế toán Việt Nam) dựa trên các phiên bản IAS cũ hơn và chưa hội tụ hoàn toàn với IFRS. Một số quy định của VAS, như tiêu chí ghi nhận doanh thu dựa trên quy tắc và các phương pháp khấu hao được quy định sẵn, hạn chế một số hình thức tùy ý nhưng lại tạo ra những cơ hội có thể dự đoán cho các hình thức khác.
Hành vi vượt ngưỡng chuẩn.Burgstahler và Dichev (1997) ghi nhận sự gián đoạn quanh mức lợi nhuận bằng không và mức thay đổi lợi nhuận bằng không trong dữ liệu Hoa Kỳ. Thị trường Việt Nam, với mức độ tham gia cao của nhà đầu tư cá nhân và sự chú trọng vào lợi nhuận hiển thị, có thể cho thấy những mô thức tương tự hoặc thậm chí rõ nét hơn.
27.1 Các mô hình về dồn tích không tùy ý
27.1.1 Ký hiệu và thiết lập
Gọi \(i\) là chỉ số doanh nghiệp và \(t\) là chỉ số năm tài chính. Ta định nghĩa:
Bảng 27.1: Ký hiệu cho các mô hình quản trị lợi nhuận
Ký hiệu
Định nghĩa
\(TA_{i,t}\)
Tổng dồn tích (chia cho tài sản năm trước)
\(NDA_{i,t}\)
Dồn tích không tùy ý (dự báo của mô hình)
\(DA_{i,t}\)
Dồn tích tùy ý: \(DA_{i,t} = TA_{i,t} - NDA_{i,t}\)
\(A_{i,t}\)
Tổng tài sản
\(\Delta Rev_{i,t}\)
Thay đổi doanh thu, chia cho \(A_{i,t-1}\)
\(\Delta Rec_{i,t}\)
Thay đổi các khoản phải thu ròng, chia cho \(A_{i,t-1}\)
\(PPE_{i,t}\)
Tài sản cố định hữu hình gộp (nguyên giá), chia cho \(A_{i,t-1}\)
\(PART_{i,t}\)
Biến chỉ báo bằng 1 cho năm kiểm định (năm sự kiện)
Tổng dồn tích được tính theo phương pháp bảng cân đối kế toán:
trong đó \(\Delta CA\) là thay đổi tài sản ngắn hạn, \(\Delta Cash\) là thay đổi tiền mặt, \(\Delta CL\) là thay đổi nợ ngắn hạn phải trả, \(\Delta STD\) là thay đổi nợ vay ngắn hạn, và \(Dep\) là chi phí khấu hao.
27.1.2 Năm mô hình
Chúng ta triển khai năm mô hình, mỗi mô hình ước lượng \(NDA\) trong một cửa sổ ước lượng riêng của từng doanh nghiệp và tính \(DA\) cho năm kiểm định như phần dư.
Mô hình 1: Healy (1985). Dồn tích không tùy ý bằng trung bình của tổng dồn tích trong kỳ ước lượng:
Đây là chuẩn so sánh đơn giản nhất có thể. Hạn chế của nó rất rõ: nó coi mọi biến thiên theo thời gian của dồn tích là tùy ý, kể cả biến thiên do sự thay đổi môi trường kinh tế của doanh nghiệp gây ra.
Mô hình 2: DeAngelo (1986). Dồn tích không tùy ý bằng tổng dồn tích của kỳ trước:
\[
NDA^{DeAngelo}_{i,t} = TA_{i,t-1}
\tag{27.3}\]
Điều này tương đương với giả định rằng thay đổi của tổng dồn tích hoàn toàn là tùy ý. Mô hình hoạt động tốt khi dồn tích tuân theo bước ngẫu nhiên, nhưng kém khi chúng có xu hướng hồi quy về trung bình hoặc có xu thế.
Mô hình 3: Jones (1991). Mô hình này kiểm soát sự thay đổi của môi trường kinh tế doanh nghiệp bằng cách hồi quy dồn tích theo thay đổi doanh thu và mức tài sản cố định:
Các tham số \(\hat{\alpha}_1, \hat{\alpha}_2, \hat{\alpha}_3\) được ước lượng trên dữ liệu kỳ ước lượng. Dồn tích không tùy ý của năm kiểm định là các giá trị khớp từ hồi quy này áp dụng cho các biến giải thích của năm kiểm định.
Logic kinh tế là tăng trưởng doanh thu tạo ra các khoản dồn tích vốn lưu động hợp lý (khoản phải thu và hàng tồn kho cao hơn), còn tài sản cố định đại diện cho chi phí khấu hao không tùy ý. Hệ số chặn được chia cho tài sản năm trước thay vì đưa vào như một hằng số thông thường, theo Jones (1991).
Mô hình 4: Jones điều chỉnh(Dechow, Sloan, và Sweeney 1995). Điều chỉnh này hiệu chỉnh thay đổi doanh thu theo thay đổi khoản phải thu trong năm kiểm định, với tiền đề rằng tăng trưởng doanh thu bán chịu dễ bị thao túng hơn tăng trưởng doanh thu tiền mặt:
Các hệ số vẫn được ước lượng từ mô hình Jones chưa điều chỉnh (Phương trình 27.4) trên dữ liệu kỳ ước lượng, nhưng khoản phải thu chỉ được trừ khỏi doanh thu khi tính các giá trị khớp cho năm kiểm định.
Mô hình 5: Mô hình ngành. Mô hình này giả định rằng thành phần chung của dồn tích trong một ngành phản ánh biến thiên không tùy ý:
trong đó \(\widetilde{TA}_{j,t}\) là trung vị tổng dồn tích của tất cả doanh nghiệp trong ngành \(j\) (không kể doanh nghiệp \(i\)), được ước lượng trong kỳ ước lượng.
27.1.3 Triển khai
Function to compute total accruals from balance sheet data
Implementations of five non-discretionary accrual models
def fit_healy(df: pd.DataFrame) -> pd.DataFrame:"""Healy (1985): NDA = mean accruals in estimation period.""" est_mean = df.loc[~df["part"], "acc_at"].mean() df = df.copy() df["nda_healy"] = est_mean df["da_healy"] = df["acc_at"] - df["nda_healy"]return dfdef fit_deangelo(df: pd.DataFrame) -> pd.DataFrame:"""DeAngelo (1986): NDA = prior-period total accruals.""" df = df.copy() df["nda_deangelo"] = df["acc_at"].shift(1) df["da_deangelo"] = df["acc_at"] - df["nda_deangelo"]return dfdef fit_jones(df: pd.DataFrame) -> pd.DataFrame:"""Jones (1991): Regression-based NDA controlling for revenue and PPE.""" df = df.copy() est = df[~df["part"]].dropna(subset=["acc_at", "one_at", "d_rev_at", "ppe_at"])iflen(est) <5: df["nda_jones"] = np.nan df["da_jones"] = np.nanreturn df y = est["acc_at"] X = est[["one_at", "d_rev_at", "ppe_at"]] model = sm.OLS(y, X).fit() pred_X = df[["one_at", "d_rev_at", "ppe_at"]].copy() df["nda_jones"] = model.predict(pred_X) df["da_jones"] = df["acc_at"] - df["nda_jones"]return dfdef fit_mod_jones(df: pd.DataFrame) -> pd.DataFrame:"""Modified Jones (Dechow et al., 1995): Adjust revenues for receivables.""" df = df.copy() est = df[~df["part"]].dropna(subset=["acc_at", "one_at", "d_rev_at", "ppe_at"])iflen(est) <5: df["nda_mod_jones"] = np.nan df["da_mod_jones"] = np.nanreturn df# Estimate on unadjusted Jones model y = est["acc_at"] X = est[["one_at", "d_rev_at", "ppe_at"]] model = sm.OLS(y, X).fit()# Predict using adjusted revenue (subtract receivable changes) pred_X = df[["one_at", "d_rev_alt_at", "ppe_at"]].copy() pred_X.columns = ["one_at", "d_rev_at", "ppe_at"] df["nda_mod_jones"] = model.predict(pred_X) df["da_mod_jones"] = df["acc_at"] - df["nda_mod_jones"]return dfdef fit_industry(df: pd.DataFrame) -> pd.DataFrame:"""Industry model: NDA = f(industry median accruals).""" df = df.copy() est = df[~df["part"]].dropna(subset=["acc_at", "acc_ind"])iflen(est) <5: df["nda_industry"] = np.nan df["da_industry"] = np.nanreturn df y = est["acc_at"] X = sm.add_constant(est["acc_ind"]) model = sm.OLS(y, X).fit() pred_X = sm.add_constant(df["acc_ind"]) df["nda_industry"] = model.predict(pred_X) df["da_industry"] = df["acc_at"] - df["nda_industry"]return df
Master function to apply all five models to a panel
def prepare_model_vars(df: pd.DataFrame) -> pd.DataFrame:"""Add scaled variables needed by the five NDA models.""" df = calc_accruals(df) firm_col ="ticker"if"ticker"in df.columns else"gvkey" df["sic2"] = df["sic"].astype(str).str[:2] df["acc_at"] = df["acc_raw"] / df["lag_at"] df["one_at"] =1.0/ df["lag_at"] df["d_rev_at"] = df["d_rev"] / df["lag_at"] df["d_rev_alt_at"] = (df["d_rev"] - df["d_rec"]) / df["lag_at"] df["ppe_at"] = df["ppegt"] / df["lag_at"]# Industry median accruals (estimation period only)# est_acc = df.loc[~df["part"], ["sic2", "acc_at"]].copy() est_acc = df.loc[df["part"] ==False, ["sic2", "acc_at"]].copy() ind_median = est_acc.groupby("sic2")["acc_at"].median().rename("acc_ind") df = df.merge(ind_median, on="sic2", how="left")return dfdef get_all_nda(df: pd.DataFrame) -> pd.DataFrame:""" Apply all five NDA models on a firm-by-firm basis. Returns a DataFrame with DA columns for each model. """ firm_col ="ticker"if"ticker"in df.columns else"gvkey" year_col ="year"if"year"in df.columns else"fyear" df_mod = prepare_model_vars(df) df_mod["part"] = df_mod["part"].astype(bool) results = []for firm, group in df_mod.groupby(firm_col): g = group.sort_values(year_col).copy() g = fit_healy(g) g = fit_deangelo(g) g = fit_jones(g) g = fit_mod_jones(g) g = fit_industry(g) results.append(g)return pd.concat(results, ignore_index=True)
27.1.4 Hiệu chỉnh Salkever (1976)
Một vấn đề phương pháp quan trọng nhưng ít được chú ý nảy sinh khi tính sai số chuẩn cho dồn tích tùy ý theo các mô hình dạng Jones. Trong quy trình hai giai đoạn tiêu chuẩn, nhà nghiên cứu trước hết ước lượng mô hình Jones trên kỳ ước lượng, rồi tính dồn tích tùy ý cho năm kiểm định như một sai số dự báo. Nhưng sai số chuẩn của sai số dự báo lớn hơn sai số chuẩn của phần dư khớp, vì nó bao hàm sự bất định của tham số từ ước lượng giai đoạn đầu. Bỏ qua sự khác biệt này dẫn đến sai số chuẩn bị đánh giá thấp và tỷ lệ bác bỏ bị thổi phồng, chính là vấn đề đã được ghi nhận trong Dechow, Sloan, và Sweeney (1995).
Salkever (1976) đưa ra một giải pháp thanh lịch: chạy một hồi quy duy nhất trên kỳ ước lượng và kỳ kiểm định gộp lại, có thêm biến giả \(PART\) cho năm kiểm định. Hệ số của \(PART\) bằng sai số dự báo (dồn tích tùy ý), và sai số chuẩn của nó phản ánh đúng sự bất định ước lượng của giai đoạn đầu.
Với mô hình Jones, hồi quy một giai đoạn của Salkever là:
Hệ số \(\hat{\delta}\) giống hệt về số học với ước lượng \(DA\) hai giai đoạn, nhưng sai số chuẩn \(\text{se}(\hat{\delta})\) của nó là sai số chuẩn đúng của sai số dự báo.
Demonstration of the Salkever (1976) equivalence
def demonstrate_salkever(df_firm: pd.DataFrame) -> pd.DataFrame:""" For a single firm, show that the two-stage Jones DA equals the Salkever one-stage coefficient on PART. """ df = prepare_model_vars(df_firm) needed = ["acc_at", "one_at", "d_rev_at", "ppe_at", "part"] df = df.dropna(subset=needed).copy()# ── Two-stage approach ── est = df[~df["part"]] y_est = est["acc_at"] X_est = est[["one_at", "d_rev_at", "ppe_at"]] fm_stage1 = sm.OLS(y_est, X_est).fit() df["nda_two_stage"] = fm_stage1.predict(df[["one_at", "d_rev_at", "ppe_at"]]) df["da_two_stage"] = df["acc_at"] - df["nda_two_stage"]# Test-year DA from two-stage da_two_stage = df.loc[df["part"], "da_two_stage"].values# ── Salkever one-stage ── df["part_float"] = df["part"].astype(float) y_full = df["acc_at"] X_full = df[["one_at", "d_rev_at", "ppe_at", "part_float"]] fm_salkever = sm.OLS(y_full, X_full).fit() da_salkever = fm_salkever.params["part_float"] se_two_stage_wrong = np.nan # two-stage doesn't give correct SE se_salkever = fm_salkever.bse["part_float"]return pd.DataFrame({"Method": ["Two-stage Jones", "Salkever one-stage"],"DA estimate": [da_two_stage[0] iflen(da_two_stage) else np.nan, da_salkever],"Correct SE": ["Not available", f"{se_salkever:.6f}"],"t-statistic": ["Biased", f"{fm_salkever.tvalues['part_float']:.4f}"], })
27.2 Sai lầm loại I dưới giả thuyết không
27.2.1 Thiết kế thực nghiệm
Để đánh giá liệu năm mô hình có cho ra các thống kê kiểm định được hiệu chỉnh tốt hay không, chúng ta tiến hành một thực nghiệm mô phỏng song song với Bảng 2 của Dechow, Sloan, và Sweeney (1995). Quy trình như sau:
Tạo một bảng dữ liệu (panel) gồm \(N\) doanh nghiệp, mỗi doanh nghiệp có \(T\) năm dữ liệu báo cáo tài chính.
Với mỗi doanh nghiệp, chọn ngẫu nhiên một năm làm năm kiểm định (\(PART = 1\)). Theo cách xây dựng, không có quản trị lợi nhuận nào xảy ra trong năm này.
Ước lượng dồn tích tùy ý bằng từng mô hình trong năm mô hình.
Hồi quy \(DA\) theo \(PART\) cho từng doanh nghiệp và ghi nhận liệu giả thuyết không \(H_0:
\delta = 0\) có bị bác bỏ ở mức ý nghĩa 5% và 1% hay không.
Tính tỷ lệ bác bỏ trên toàn bộ \(N\) doanh nghiệp.
Nếu mô hình được xác định đúng, tỷ lệ bác bỏ phải bằng mức ý nghĩa danh nghĩa của kiểm định (5% hoặc 1%). Việc bác bỏ quá mức một cách hệ thống cho thấy mô hình tạo ra các thống kê kiểm định chệch, một khiếm khuyết nghiêm trọng đối với nghiên cứu dựa vào các thước đo này để đưa ra suy luận nhân quả.
27.2.2 Tạo dữ liệu
Chúng ta tạo dữ liệu panel tổng hợp giữ được các tính chất chính theo mặt cắt ngang và chuỗi thời gian của các doanh nghiệp niêm yết Việt Nam, đồng thời cho phép ta biết chắc chắn rằng không có thao túng nào tồn tại.
Generate synthetic Vietnamese panel data for Type I error analysis
def generate_em_panel( n_firms: int=500, n_years: int=15, seed: int=2024,) -> pd.DataFrame:""" Generate a synthetic panel of Vietnamese-style financial data. No earnings management is present by construction. The data generation process captures: - AR(1) revenue process - Accruals driven by revenue growth and PPE levels - Industry-level common shocks - SOE/non-SOE heterogeneity """ rng = np.random.default_rng(seed) industries = [10, 20, 25, 41, 46, 47, 52, 62, 64, 68] records = []for i inrange(n_firms):# Firm characteristics sic = rng.choice(industries) is_soe =int(rng.random() <0.30) base_assets = rng.lognormal(mean=12, sigma=1.5) # VND billions growth_rate = rng.normal(0.08, 0.04)# Jones model parameters (firm-specific true DGP) true_alpha1 = rng.normal(0, 0.02) true_alpha2 = rng.normal(0.06, 0.03) # revenue-accrual sensitivity true_alpha3 = rng.normal(-0.04, 0.02) # depreciation effect at_prev = base_assets sale_prev = base_assets * rng.uniform(0.5, 1.5) rect_prev = sale_prev * rng.uniform(0.05, 0.25)for t inrange(n_years): year =2009+ t# Evolve fundamentals at = at_prev * (1+ growth_rate + rng.normal(0, 0.05)) sale = sale_prev * (1+ rng.normal(0.06, 0.08)) rect = sale * rng.uniform(0.05, 0.25) ppegt = at * rng.uniform(0.3, 0.7)# Generate accruals from true Jones DGP + noise d_rev = sale - sale_prev one_at =1.0/ at_prev d_rev_at = d_rev / at_prev ppe_at = ppegt / at_prev acc_at = (true_alpha1 * one_at + true_alpha2 * d_rev_at + true_alpha3 * ppe_at+ rng.normal(0, 0.03)) acc_raw = acc_at * at_prev# Reverse-engineer balance sheet items consistent with accruals dp = ppegt * rng.uniform(0.05, 0.12) d_cl = rng.normal(0, at *0.02) d_std = rng.normal(0, at *0.01) d_cash = rng.normal(0, at *0.02) d_ca = acc_raw + dp + d_cl - d_std + d_cash act = at * rng.uniform(0.3, 0.6) che = act * rng.uniform(0.05, 0.2) lct = at * rng.uniform(0.15, 0.35) dlc = lct * rng.uniform(0.1, 0.4) ni = sale * rng.uniform(0.03, 0.12) ib = ni records.append({"ticker": f"VN{i:04d}","fyear": year,"at": at,"act": act,"che": che,"lct": lct,"dlc": dlc,"dp": dp,"sale": sale,"rect": rect,"ppegt": ppegt,"ni": ni,"ib": ib,"sic": sic,"is_soe": is_soe, }) at_prev = at sale_prev = sale rect_prev = rect df = pd.DataFrame(records)return dfpanel_raw = generate_em_panel(n_firms=500, n_years=15, seed=2024)print(f"Panel: {panel_raw.shape[0]:,} firm-years, "f"{panel_raw['ticker'].nunique()} firms")
Panel: 7,500 firm-years, 500 firms
27.2.3 Xây dựng mẫu
Chúng ta xây dựng một mẫu gồm 500 doanh nghiệp, mỗi doanh nghiệp có một năm kiểm định được chọn ngẫu nhiên, mô phỏng thiết kế của Dechow, Sloan, và Sweeney (1995).
Construct analysis sample with random test-year assignment
def construct_sample( df: pd.DataFrame, n_sample: int=500, min_est_years: int=10, seed: int=42, selection_filter: Optional[callable] =None,) -> pd.DataFrame:""" For each firm, randomly assign one year as the test year (part=True). Require at least min_est_years of estimation data. """ rng = np.random.default_rng(seed) firm_col ="ticker" year_col ="fyear"# Compute accruals and filter for data availability df = calc_accruals(df) required = ["acc_raw", "lag_at", "d_rev", "d_rec", "ppegt"] df = df.dropna(subset=required) df = df[df["lag_at"] >0]# Require minimum years firm_counts = df.groupby(firm_col)[year_col].count() eligible = firm_counts[firm_counts >= (min_est_years +1)].index df = df[df[firm_col].isin(eligible)]if selection_filter isnotNone: df = selection_filter(df)# Sample n_sample firms firms = df[firm_col].unique()iflen(firms) > n_sample: firms = rng.choice(firms, n_sample, replace=False) df = df[df[firm_col].isin(firms)].copy()# For each firm, randomly pick one test year (not the first year) parts = []for firm, group in df.groupby(firm_col): years = group[year_col].sort_values().valuesiflen(years) <2:continue test_year = rng.choice(years[1:]) parts.append({firm_col: firm, year_col: test_year, "part": True}) part_df = pd.DataFrame(parts) df = df.merge(part_df, on=[firm_col, year_col], how="left") df["part"] = df["part"].fillna(False) df["part"] = df["part"].astype(bool)return dfsample_1 = construct_sample(panel_raw, n_sample=500, seed=2024)print(f"Sample 1: {sample_1.shape[0]:,} firm-years, "f"{sample_1['ticker'].nunique()} firms, "f"{sample_1['part'].sum()} test years")
Sample 1: 7,000 firm-years, 500 firms, 500 test years
27.2.4 Ước lượng dồn tích tùy ý
Apply all five models to Sample 1
da_results = get_all_nda(sample_1)# Verify: peek at test-year DA across modelsda_cols = ["da_healy", "da_deangelo", "da_jones", "da_mod_jones", "da_industry"]test_da = da_results[da_results["part"]][da_cols]print("Test-year discretionary accruals (first 5 firms):")test_da.head().round(4)
Test-year discretionary accruals (first 5 firms):
da_healy
da_deangelo
da_jones
da_mod_jones
da_industry
4
-0.0791
-0.1320
-0.1252
-0.1511
-0.0791
23
-0.0792
0.0813
-0.1799
-0.1426
-0.0792
30
0.0618
0.1403
0.1458
0.1308
0.0618
45
0.2106
0.2069
0.0578
0.5023
0.2106
61
-0.1326
0.0865
-0.1425
-0.1193
-0.1326
27.2.5 Hồi quy cấp doanh nghiệp và tỷ lệ bác bỏ
Với mỗi doanh nghiệp và mỗi mô hình, chúng ta hồi quy \(DA\) theo \(PART\) và ghi nhận liệu giả thuyết không về dồn tích tùy ý bằng không trong năm kiểm định có bị bác bỏ hay không.
Compute firm-specific t-statistics and rejection rates
def firm_regressions(df: pd.DataFrame, models: list[str]) -> pd.DataFrame:""" For each firm and model, regress DA on PART. Return coefficients, std errors, t-stats, and rejection indicators. """ firm_col ="ticker"if"ticker"in df.columns else"gvkey" records = []for firm, group in df.groupby(firm_col):for model in models: da_col =f"da_{model}" g = group.dropna(subset=[da_col]).copy() g["part_float"] = g["part"].astype(float)iflen(g) <5or g["part"].sum() ==0:continuetry: fm = sm.OLS( g[da_col], sm.add_constant(g["part_float"]) ).fit() coef = fm.params["part_float"] se = fm.bse["part_float"] t_stat = fm.tvalues["part_float"] df_resid = fm.df_resid# One-sided p-values p_neg = stats.t.cdf(t_stat, df_resid) p_pos =1- p_neg records.append({ firm_col: firm,"model": model,"coef": coef,"se": se,"t_stat": t_stat,"neg_p01": p_neg <0.01,"neg_p05": p_neg <0.05,"pos_p01": p_pos <0.01,"pos_p05": p_pos <0.05, })exceptException:continuereturn pd.DataFrame(records)models = ["healy", "deangelo", "jones", "mod_jones", "industry"]reg_results = firm_regressions(da_results, models)
27.2.6 Kết quả
Bảng 27.2 báo cáo phân phối của các hệ số ước lượng trên \(PART\) qua các doanh nghiệp. Dưới giả thuyết không là không có thao túng, ta kỳ vọng hệ số trung bình xấp xỉ bằng không.
Bảng 27.2: Phân phối các ước lượng dồn tích tùy ý cấp doanh nghiệp (hệ số trên PART) dưới giả thuyết không là không có quản trị lợi nhuận. Cả năm mô hình đều cho ước lượng trung bình gần bằng không, như kỳ vọng.
Mean
Std Dev
Q1
Median
Q3
Model
deangelo
0.0110
0.2584
-0.1604
0.0140
0.1839
healy
0.0047
0.1506
-0.0993
0.0050
0.1066
industry
0.0047
0.1506
-0.0993
0.0050
0.1066
jones
0.0035
0.1739
-0.1134
0.0069
0.1125
mod_jones
0.0068
0.1807
-0.1127
0.0108
0.1177
Bảng 27.3 báo cáo tỷ lệ bác bỏ. So sánh then chốt là liệu các tỷ lệ này có xấp xỉ mức ý nghĩa danh nghĩa của kiểm định hay không.
Bảng 27.3: Tỷ lệ sai lầm loại I của các kiểm định một phía về quản trị lợi nhuận dưới giả thuyết không. Tỷ lệ vượt mức ý nghĩa danh nghĩa (5% hoặc 1%) cho thấy mô hình bác bỏ quá mức, một mối quan ngại đáng kể đối với các mô hình Jones và Jones điều chỉnh.
Neg (1%)
Neg (5%)
Pos (1%)
Pos (5%)
Model
deangelo
0.0109
0.0457
0.0043
0.0478
healy
0.0100
0.0380
0.0080
0.0500
industry
0.0100
0.0380
0.0080
0.0500
jones
0.0280
0.0800
0.0380
0.1000
mod_jones
0.0320
0.0740
0.0300
0.0900
27.2.7 Kiểm định nhị thức cho sai lệch mức ý nghĩa thực tế của kiểm định
Chúng ta kiểm định chính thức liệu các tỷ lệ bác bỏ quan sát được có khác mức ý nghĩa danh nghĩa hay không bằng kiểm định nhị thức hai phía. Giá trị \(p\) nhỏ cho thấy thống kê kiểm định bị hiệu chỉnh sai đáng kể.
Hiện mã
def binom_test_rate(series: pd.Series, nominal: float) ->float:"""Two-sided binomial test for rejection rate = nominal.""" x = series.dropna() k =int(x.sum()) n =len(x)if n ==0:return np.nanreturn stats.binomtest(k, n, nominal, alternative="two-sided").pvaluebinom_results = {}for model, group in reg_results.groupby("model"): binom_results[model] = {"Neg (1%)": binom_test_rate(group["neg_p01"], 0.01),"Neg (5%)": binom_test_rate(group["neg_p05"], 0.05),"Pos (1%)": binom_test_rate(group["pos_p01"], 0.01),"Pos (5%)": binom_test_rate(group["pos_p05"], 0.05), }binom_df = pd.DataFrame(binom_results).T.round(4)binom_df.index.name ="Model"binom_df
Bảng 27.4: Giá trị p của kiểm định nhị thức về việc tỷ lệ bác bỏ có bằng mức ý nghĩa danh nghĩa hay không. Giá trị nhỏ (ví dụ < 0.05) cho thấy mức ý nghĩa thực tế lệch khỏi mức danh nghĩa một cách có ý nghĩa thống kê.
Neg (1%)
Neg (5%)
Pos (1%)
Pos (5%)
Model
deangelo
0.8117
0.7486
0.3423
0.9150
healy
1.0000
0.2581
0.8236
1.0000
industry
1.0000
0.2581
0.8236
1.0000
jones
0.0006
0.0038
0.0000
0.0000
mod_jones
0.0001
0.0179
0.0002
0.0002
Diễn giải việc bác bỏ quá mức
Nếu các mô hình Jones và Jones điều chỉnh cho thấy tỷ lệ bác bỏ cao hơn 5% một cách có ý nghĩa, điều này báo hiệu rằng quy trình hai giai đoạn tiêu chuẩn tạo ra các thống kê kiểm định phản bảo thủ (anti-conservative). Hiệu chỉnh của Salkever (1976) giải quyết vấn đề này bằng cách tính sai số chuẩn phản ánh sự bất định ước lượng của giai đoạn đầu. Trong nghiên cứu thực tế về các doanh nghiệp Việt Nam, nơi chuỗi quan sát theo từng doanh nghiệp thường ngắn (10–15 năm lịch sử niêm yết), hiệu chỉnh này đặc biệt quan trọng vì phương sai sai số dự báo chiếm tỷ trọng lớn hơn trong phương sai phần dư khi số quan sát kỳ ước lượng ít hơn.
27.3 Các doanh nghiệp có kết quả hoạt động cực đoan
Một điểm yếu quen thuộc của các mô hình dựa trên dồn tích là hiệu quả kém khi các doanh nghiệp kiểm định trải qua kết quả kinh tế cực đoan. Dechow, Sloan, và Sweeney (1995) ghi nhận rằng cả năm mô hình đều bác bỏ quá mức giả thuyết không khi các quan sát doanh nghiệp–năm kiểm định được lấy từ phần đuôi của phân phối lợi nhuận hoặc dòng tiền. Kothari, Leone, và Wasley (2005) sau đó đề xuất “ghép cặp theo hiệu quả hoạt động” (performance matching) như một biện pháp khắc phục một phần.
Trực giác của vấn đề khá đơn giản: mô hình Jones giả định một quan hệ tuyến tính, đối xứng giữa thay đổi doanh thu và dồn tích. Nhưng các doanh nghiệp trải qua tăng trưởng hoặc suy giảm cực đoan tạo ra các khoản dồn tích lệch phi tuyến khỏi dự báo của mô hình, ngay cả khi không có bất kỳ thao túng nào. Tính phi tuyến này bị quy nhầm cho dồn tích tùy ý.
27.3.1 Xây dựng các mẫu có kết quả hoạt động cực đoan
Construct samples from top and bottom earnings deciles
Bảng 27.5: Tỷ lệ sai lầm loại I (một phía, 5%) khi các quan sát doanh nghiệp–năm kiểm định được lấy từ các thập phân vị lợi nhuận cực đoan. Việc bác bỏ quá mức là điều được kỳ vọng vì các mô hình dồn tích quy nhầm biến thiên dồn tích do kết quả hoạt động cho sự tùy ý của nhà quản lý.
Kothari, Leone, và Wasley (2005) đề xuất điều chỉnh dồn tích tùy ý bằng cách trừ đi DA của một doanh nghiệp được ghép cặp theo hiệu quả hoạt động (cùng ngành và có ROA tương tự). Cách này loại bỏ thành phần hệ thống của dồn tích có tương quan với hiệu quả hoạt động. Dồn tích tùy ý sau ghép cặp là:
trong đó \(i^*\) là doanh nghiệp đối chứng được ghép cặp. Cách tiếp cận này đặc biệt phù hợp với Việt Nam, nơi mặt cắt ngang các doanh nghiệp niêm yết gồm nhiều doanh nghiệp tăng trưởng cao bên cạnh các DNNN trì trệ, một sự không đồng nhất về hiệu quả hoạt động mà các mô hình tiêu chuẩn có thể mô tả sai.
27.4 Phân tích sức mạnh kiểm định
27.4.1 Đưa quản trị lợi nhuận nhân tạo vào dữ liệu
Một mô hình không bao giờ bác bỏ là vô dụng dù tỷ lệ sai lầm loại I của nó hoàn hảo. Chúng ta cần đánh giá sức mạnh kiểm định (power): xác suất phát hiện thao túng khi nó thực sự tồn tại. Theo Dechow, Sloan, và Sweeney (1995), chúng ta đưa vào báo cáo tài chính của năm kiểm định một lượng thao túng nhân tạo đã biết và đo tỷ lệ phát hiện.
Chúng ta xét ba hình thức thao túng ở các mức độ khác nhau:
Thao túng chi phí. Giảm nợ ngắn hạn phải trả đi một lượng bằng mức thao túng (ví dụ: trì hoãn ghi nhận chi phí phải trả): \[LCT'_{i,t} = LCT_{i,t} - \lambda \cdot A_{i,t-1}\]
Thao túng doanh thu. Tăng doanh thu và khoản phải thu một lượng bằng mức thao túng (ví dụ: ghi nhận doanh thu sớm hoặc nhồi hàng vào kênh phân phối): \[Sale'_{i,t} = Sale_{i,t} + \lambda \cdot A_{i,t-1}, \quad Rect'_{i,t} = Rect_{i,t} + \lambda \cdot A_{i,t-1}\]
Thao túng biên lợi nhuận. Tăng doanh thu một lượng gộp cần thiết để thổi phồng lợi nhuận ròng thêm \(\lambda \cdot A_{i,t-1}\), đồng thời tăng cả khoản phải thu và nợ ngắn hạn phải trả theo tỷ lệ.
Tham số \(\lambda\) biểu thị mức thao túng dưới dạng tỷ lệ của tổng tài sản năm trước, dao động từ 0% đến 50%.
Function to introduce artificial manipulation
def manipulate( df: pd.DataFrame, level: float=0.0, manip_type: str="expense",) -> pd.DataFrame:""" Introduce artificial earnings management of a given type and level into test-year (part=True) observations. Parameters ---------- df : DataFrame with 'part' indicator and required financial variables. level : Manipulation as fraction of lagged total assets. manip_type : One of 'expense', 'revenue', 'margin'. """ firm_col ="ticker"if"ticker"in df.columns else"gvkey" year_col ="fyear"if"fyear"in df.columns else"year" df = df.sort_values([firm_col, year_col]).copy() g = df.groupby(firm_col) lag_at = g["at"].shift(1) manip_amt = lag_at * levelif manip_type =="expense":# Decrease current liabilities in test year df.loc[df["part"], "lct"] -= manip_amt[df["part"]]elif manip_type =="revenue":# Increase sales and receivables in test year df.loc[df["part"], "sale"] += manip_amt[df["part"]] df.loc[df["part"], "rect"] += manip_amt[df["part"]] df.loc[df["part"], "act"] += manip_amt[df["part"]]# Reverse in following year next_part = g["part"].shift(1).fillna(False) df.loc[next_part, "sale"] -= manip_amt[next_part]elif manip_type =="margin":# Compute net income ratio for scaling est_mask =~df["part"] ni_ratio = g.apply(lambda x: (x.loc[~x["part"], "ni"] / x.loc[~x["part"], "sale"]).median() ) df["_ni_ratio"] = df[firm_col].map(ni_ratio) gross_amt = np.where( df["_ni_ratio"] >0, manip_amt / df["_ni_ratio"], 0 ) df.loc[df["part"], "sale"] += gross_amt[df["part"]] df.loc[df["part"], "rect"] += gross_amt[df["part"]] df.loc[df["part"], "act"] += gross_amt[df["part"]] net_effect = gross_amt - manip_amt df.loc[df["part"], "lct"] += net_effect[df["part"]] df.drop(columns=["_ni_ratio"], inplace=True)return df
Power analysis across manipulation levels and types
levels = [0.0, 0.05, 0.10, 0.20, 0.30, 0.50]manip_types = ["expense", "revenue", "margin"]power_records = []for level in levels:for mtype in manip_types:# Copy base sample and introduce manipulation manip_sample = sample_1.copy()if level >0: manip_sample = manipulate(manip_sample, level=level, manip_type=mtype)# Estimate DA and run tests da = get_all_nda(manip_sample) regs = firm_regressions(da, models)# Power = positive one-sided rejection rate at 5% power = regs.groupby("model")["pos_p05"].mean()for model_name, pwr in power.items(): power_records.append({"level": level,"type": mtype,"model": model_name,"power": pwr, })power_df = pd.DataFrame(power_records)
Power analysis across manipulation levels and types
levels = [0.0, 0.05, 0.10, 0.20, 0.30, 0.50]manip_types = ["expense", "revenue", "margin"]from joblib import Parallel, delayedfrom itertools import productdef _run_one(level, mtype, base_sample, models): manip_sample = base_sample.copy()if level >0: manip_sample = manipulate(manip_sample, level=level, manip_type=mtype) da = get_all_nda(manip_sample) regs = firm_regressions(da, models) power = regs.groupby("model")["pos_p05"].mean()return [ {"level": level, "type": mtype, "model": m, "power": p}for m, p in power.items() ]# Skip redundant level=0 runs (all manip_types identical when level=0)combos = [(0.0, "expense")] + [ (l, m) for l in levels if l >0for m in manip_types]results = Parallel(n_jobs=-1, verbose=1)( delayed(_run_one)(lvl, mt, sample_1, models)for lvl, mt in combos)# Expand level=0 result across all manip_typesflat = []for (lvl, mt), batch inzip(combos, results):if lvl ==0:for mtype in manip_types: flat.extend([{**r, "type": mtype} for r in batch])else: flat.extend(batch)power_df = pd.DataFrame(flat)
[Parallel(n_jobs=-1)]: Using backend LokyBackend with 16 concurrent workers.
[Parallel(n_jobs=-1)]: Done 2 out of 16 | elapsed: 1.4min remaining: 10.1min
[Parallel(n_jobs=-1)]: Done 16 out of 16 | elapsed: 1.5min finished
27.4.2 Các hàm sức mạnh kiểm định
Hình 27.1 vẽ các hàm sức mạnh kiểm định ước lượng được. Các câu hỏi then chốt là: (i) mô hình nào có sức mạnh cao nhất với một mức và loại thao túng cho trước, và (ii) ở quy mô nào thì thao túng trở nên có thể phát hiện một cách đáng tin cậy?
Hình 27.1: Các hàm sức mạnh kiểm định của năm mô hình phát hiện quản trị lợi nhuận qua ba loại thao túng. Sức mạnh tăng theo quy mô thao túng nhưng vẫn thấp ở các mức hợp lý về mặt kinh tế (< 10% tài sản), cho thấy khó khăn căn bản của việc phát hiện quản trị lợi nhuận.
27.4.3 Thống kê tóm tắt
Bảng 27.6 báo cáo sức mạnh kiểm định tại một số mức thao túng chọn lọc cho các mô hình Jones và Jones điều chỉnh, là hai mô hình được dùng phổ biến nhất trong nghiên cứu ứng dụng.
Bảng 27.6: Sức mạnh kiểm định của các mô hình Jones và Jones điều chỉnh tại một số mức thao túng chọn lọc. Ngay cả ở mức 10% tài sản, một lượng thao túng lớn, tỷ lệ phát hiện vẫn thấp hơn nhiều so với 50% với hầu hết các loại thao túng, nhấn mạnh sức mạnh thống kê thấp của các kiểm định tiêu chuẩn.
type
expense
margin
revenue
Model
Level (% assets)
jones
0.00
0.100
0.100
0.100
0.05
0.154
0.132
0.142
0.10
0.218
0.126
0.178
0.20
0.432
0.122
0.300
0.30
0.660
0.122
0.436
0.50
0.912
0.122
0.710
mod_jones
0.00
0.090
0.090
0.090
0.05
0.130
0.106
0.128
0.10
0.198
0.174
0.190
0.20
0.404
0.368
0.422
0.30
0.636
0.598
0.652
0.50
0.884
0.878
0.922
Hàm ý cho nghiên cứu về Việt Nam
Phân tích sức mạnh kiểm định có những hàm ý rõ rệt đối với nghiên cứu quản trị lợi nhuận ở Việt Nam. Một doanh nghiệp niêm yết Việt Nam điển hình đã niêm yết 10–15 năm, cung cấp ít quan sát kỳ ước lượng hơn nhiều so với bối cảnh Hoa Kỳ, nơi Dechow, Sloan, và Sweeney (1995) có hàng thập kỷ dữ liệu Compustat. Cửa sổ ước lượng ngắn hơn làm tăng sự bất định tham số trong mô hình Jones, làm giảm thêm sức mạnh kiểm định. Kết hợp với dữ liệu tài chính nhiễu hơn vốn phổ biến ở các thị trường mới nổi, nhà nghiên cứu nên diễn giải việc không bác bỏ giả thuyết không là không mang thông tin, thay vì là bằng chứng cho thấy báo cáo tài chính trong sạch.
27.5 Bối cảnh thể chế Việt Nam
27.5.1 Các kênh quản trị lợi nhuận
Một số đặc điểm của môi trường thể chế Việt Nam tạo ra những động cơ và cơ hội quản trị lợi nhuận đặc thù:
Thao túng do thuế. Thuế suất thuế thu nhập doanh nghiệp (CIT) của Việt Nam đã giảm từ 28% (trước năm 2009) xuống 20% (từ năm 2016 trở đi), kèm các mức ưu đãi cho doanh nghiệp trong Khu kinh tế đặc biệt và các ngành công nghệ cao. Sự gắn kết chặt chẽ giữa kế toán VAS và kế toán thuế tạo động cơ quản trị lợi nhuận theo hướng giảm để giảm nghĩa vụ thuế, một mô thức đã được ghi nhận ở các nền kinh tế đang phát triển có truyền thống kế toán theo luật thành văn (Ball, Robin, và Wu 2003).
Động cơ IPO và phát hành thêm cổ phiếu (SEO). Việt Nam đã trải qua nhiều làn sóng cổ phần hóa DNNN (tư nhân hóa một phần). Các nhà quản lý có động cơ thổi phồng lợi nhuận trước các đợt chào bán cổ phiếu để tối đa hóa số tiền thu được. SSC yêu cầu các ngưỡng lợi nhuận tối thiểu để đủ điều kiện niêm yết, tạo ra động cơ mạnh quanh các ngưỡng quy định này, vốn là bối cảnh tự nhiên cho phân tích gián đoạn của Burgstahler và Dichev (1997). Sự tùy ý kế toán quanh các đợt IPO không chỉ giới hạn ở lợi nhuận báo cáo: nó mở rộng sang việc định giá thù lao bằng cổ phần trước IPO. Badertscher và c.s. (2026) nghiên cứu “cheap stock” (cổ phiếu giá rẻ)—thù lao bằng cổ phần được cấp trước IPO với giá thực hiện thấp hơn nhiều so với giá chào bán cuối cùng (trong mẫu Hoa Kỳ của họ, giá IPO cao hơn giá thực hiện quyền chọn trước IPO hơn năm lần)—và chỉ ra rằng việc định giá thấp cổ phiếu trước IPO cho phép doanh nghiệp báo cáo chi phí thù lao nhỏ hơn trong khi chuyển giao một lượng giá trị đáng kể cho nội bộ. Quan trọng hơn, họ ghi nhận rằng cheap stock có những hệ quả thực: các doanh nghiệp sử dụng nó có thù lao CEO cao hơn (tính theo giá IPO), đầu tư sau IPO thấp hơn, lợi nhuận cổ phiếu sau IPO yếu hơn và mức định giá thấp khi IPO lớn hơn. Cơ chế này rất phù hợp với các đợt IPO cổ phần hóa ở Việt Nam, nơi việc phân bổ cổ phần cho nội bộ ở mức giá ưu đãi trước khi niêm yết là mối quan ngại quản trị công ty lặp đi lặp lại và nơi việc định giá quyền chọn cổ phần của nhân viên và ban quản lý trước khi niêm yết còn mang tính tùy ý đáng kể.
Quản trị lợi nhuận thực trong ngành sản xuất.Roychowdhury (2006) xác định sản xuất vượt mức, cắt giảm chi tiêu tùy ý và thao túng doanh số là ba kênh chính của quản trị lợi nhuận thực. Ngành sản xuất lớn của Việt Nam (dệt may, lắp ráp điện tử, chế biến thực phẩm) tạo nhiều dư địa cho REM dựa trên sản xuất vượt mức, trong đó chi phí đơn vị được giảm bằng cách phân bổ chi phí cố định chung lên các đợt sản xuất lớn hơn.
Related-party transactions. Transactions with affiliated entities are a well-documented channel for earnings manipulation in Asian markets. Vietnamese conglomerates (tập đoàn) often feature complex cross-ownership structures where transfer pricing between subsidiaries can shift profits across reporting entities.
27.5.2 Kiểm định phân phối lợi nhuận
Burgstahler và Dichev (1997) quan sát thấy một sự gián đoạn đáng chú ý trong phân phối lợi nhuận báo cáo quanh mức không: số doanh nghiệp báo cáo lợi nhuận dương nhỏ nhiều hơn hẳn số báo cáo khoản lỗ nhỏ, so với những gì một phân phối trơn sẽ dự báo. Mô thức này được diễn giải là bằng chứng cho thấy các doanh nghiệp quản trị lợi nhuận để tránh báo cáo lỗ.
Chúng ta áp dụng kiểm định này cho dữ liệu mô phỏng kiểu Việt Nam để minh họa phương pháp.
Hiện mã
# Generate earnings for a larger sample with benchmark-beating behaviorrng_dist = np.random.default_rng(2024)n_firms_dist =2000n_years_dist =10earnings = []for i inrange(n_firms_dist): base_earn = rng_dist.normal(0.06, 0.08)for t inrange(n_years_dist): e = base_earn + rng_dist.normal(0, 0.04)# Simulate benchmark-beating: firms near zero bump earnings upif-0.01< e <0.005: e += rng_dist.uniform(0.005, 0.015) * (rng_dist.random() <0.6) earnings.append(e)earn_array = np.array(earnings)fig, ax = plt.subplots(figsize=(8, 5))bins = np.arange(-0.30, 0.35, 0.01)ax.hist(earn_array, bins=bins, color="steelblue", edgecolor="white", alpha=0.85, density=True)ax.axvline(0, color="firebrick", linestyle="--", linewidth=1.5, label="Zero threshold")ax.set_xlabel("Earnings / Total Assets")ax.set_ylabel("Density")ax.set_title("Earnings Distribution Around Zero")ax.legend()plt.tight_layout()plt.show()
Hình 27.2: Phân phối lợi nhuận đã chia theo quy mô quanh mức không. Một sự gián đoạn, tức mật độ dư ngay trên mức không và thiếu hụt ngay dưới mức không, sẽ gợi ý hành vi vượt ngưỡng chuẩn. Đường đứt nét màu đỏ đánh dấu ngưỡng không.
Hiện mã
# Year-over-year changesearn_changes = np.diff(earn_array.reshape(n_firms_dist, n_years_dist), axis=1).flatten()fig, ax = plt.subplots(figsize=(8, 5))bins_chg = np.arange(-0.15, 0.15, 0.005)ax.hist(earn_changes, bins=bins_chg, color="darkorange", edgecolor="white", alpha=0.85, density=True)ax.axvline(0, color="firebrick", linestyle="--", linewidth=1.5, label="Zero change")ax.set_xlabel("Change in Earnings / Total Assets")ax.set_ylabel("Density")ax.set_title("Earnings Change Distribution Around Zero")ax.legend()plt.tight_layout()plt.show()
Hình 27.3: Phân phối thay đổi lợi nhuận theo năm quanh mức không. Một sự gián đoạn ở đây gợi ý rằng các doanh nghiệp quản trị lợi nhuận để tránh báo cáo sụt giảm, dù nhỏ.
27.5.3 Quản trị lợi nhuận dựa trên dồn tích so với quản trị lợi nhuận thực
Cohen, Dey, và Lys (2008) ghi nhận sự chuyển dịch từ AEM sang REM sau khi Đạo luật Sarbanes-Oxley (SOX) được thông qua năm 2002, cho thấy việc giám sát quy định chặt chẽ hơn đẩy hoạt động thao túng sang các kênh khó phát hiện hơn. Zang (2012) cung cấp thêm bằng chứng rằng các doanh nghiệp đánh đổi giữa AEM và REM dựa trên chi phí tương đối của chúng.
Ở Việt Nam, nơi việc thực thi chuẩn mực kế toán yếu hơn so với nước Mỹ thời hậu SOX, ta có thể kỳ vọng AEM vẫn là kênh chiếm ưu thế. Tuy nhiên, khi Việt Nam tiến tới áp dụng IFRS và tăng cường giám sát của SSC, giả thuyết thay thế từ AEM sang REM trở nên có thể kiểm định được.
Chúng ta có thể đo REM bằng cách tiếp cận của Roychowdhury (2006). Ba chỉ báo thay thế nắm bắt các kênh thao túng khác nhau:
Dòng tiền hoạt động bất thường. Ước lượng CFO bình thường như một hàm của doanh thu và thay đổi doanh thu:
Phần dư từ các hồi quy này đóng vai trò chỉ báo thay thế cho thao túng thực. Một doanh nghiệp sản xuất vượt mức sẽ có chi phí sản xuất cao bất thường và CFO thấp bất thường (tiền bị giam trong hàng tồn kho).
27.6 Tóm tắt
Chương này đã xem xét việc đo lường và phát hiện quản trị lợi nhuận, tập trung vào tính chặt chẽ về phương pháp luận và sự điều chỉnh cho môi trường thể chế của Việt Nam. Các điểm chính cần ghi nhớ là:
Phát hiện quản trị lợi nhuận đòi hỏi tách dồn tích tùy ý khỏi dồn tích không tùy ý, điều này phụ thuộc quyết định vào chất lượng của mô hình dồn tích không tùy ý. Cả năm mô hình kinh điển đều có những điểm yếu đã biết.
Dưới giả thuyết không là không có thao túng, các mô hình Jones và Jones điều chỉnh bác bỏ quá mức khi dùng sai số chuẩn hai giai đoạn tiêu chuẩn. Hiệu chỉnh của Salkever (1976) cho phép suy luận được hiệu chỉnh đúng.
Khi các doanh nghiệp kiểm định có kết quả tài chính cực đoan, mọi mô hình đều có mức ý nghĩa thực tế lệch nghiêm trọng khỏi mức danh nghĩa, quy nhầm biến thiên dồn tích do kết quả hoạt động cho sự tùy ý của nhà quản lý. Ghép cặp theo hiệu quả hoạt động (Kothari, Leone, và Wasley 2005) giải quyết một phần vấn đề này.
Phân tích sức mạnh kiểm định cho thấy các mức thao túng hợp lý về mặt kinh tế (dưới 10% tài sản) được phát hiện với xác suất rất thấp. Điều này đặt nghi vấn về các nghiên cứu báo cáo kết quả không bác bỏ như bằng chứng của việc không có thao túng.
Các đặc điểm thể chế của Việt Nam, như quản trị DNNN, quy tắc kế toán VAS, thực thi yếu và phạm vi kiểm toán mỏng, tạo ra bối cảnh phong phú cho nghiên cứu quản trị lợi nhuận, nhưng các thách thức phương pháp luận bị khuếch đại bởi chuỗi thời gian ngắn hơn và dữ liệu nhiễu hơn.
Các nhà nghiên cứu làm việc với dữ liệu Việt Nam nên: (i) dùng hiệu chỉnh Salkever để suy luận đúng, (ii) triển khai ghép cặp theo hiệu quả hoạt động, (iii) xem xét nhiều mô hình và đối chiếu chéo kết quả, và (iv) bổ sung cho các phương pháp dựa trên dồn tích bằng quản trị lợi nhuận thực và các kiểm định về phân phối.
Badertscher, Brad A, Bjørn N Jørgensen, Sharon P Katz, và Jeremy Michels. 2026. “Cheap stock options: Antecedents and outcomes”. Management Science. https://doi.org/10.1287/mnsc.2024.06121.
Ball, Ray, Ashok Robin, và Joanna Shuang Wu. 2003. “Incentives versus standards: properties of accounting income in four East Asian countries”. Journal of accounting and economics 36 (1-3): 235–70. https://doi.org/10.1016/j.jacceco.2003.10.003.
Burgstahler, David, và Ilia Dichev. 1997. “Earnings management to avoid earnings decreases and losses”. Journal of accounting and economics 24 (1): 99–126.
Cohen, Daniel A, Aiyesha Dey, và Thomas Z Lys. 2008. “Real and accrual-based earnings management in the pre-and post-Sarbanes-Oxley periods”. The accounting review 83 (3): 757–87.
DeAngelo, Linda Elizabeth. 1986. “Accounting numbers as market valuation substitutes: A study of management buyouts of public stockholders”. Accounting review, 400–420.
Dechow, Patricia M, Richard G Sloan, và Amy P Sweeney. 1995. “Detecting earnings management”. Accounting review, 193–225.
Healy, Paul M. 1985. “The effect of bonus schemes on accounting decisions”. Journal of accounting and economics 7 (1-3): 85–107.
Jones, Jennifer J. 1991. “Earnings management during import relief investigations”. Journal of accounting research 29 (2): 193–228.
Kothari, Sagar P, Andrew J Leone, và Charles E Wasley. 2005. “Performance matched discretionary accrual measures”. Journal of accounting and economics 39 (1): 163–97.
Leuz, Christian, Dhananjay Nanda, và Peter D Wysocki. 2003. “Earnings management and investor protection: an international comparison”. Journal of financial economics 69 (3): 505–27.
Roychowdhury, Sugata. 2006. “Earnings management through real activities manipulation”. Journal of accounting and economics 42 (3): 335–70.
Salkever, David S. 1976. “The use of dummy variables to compute predictions, prediction errors, and confidence intervals”. Journal of Econometrics 4 (4): 393–97.
Zang, Amy Y. 2012. “Evidence on the trade-off between real activities manipulation and accrual-based earnings management”. The accounting review 87 (2): 675–703.
# Quản trị lợi nhuận: Phát hiện và đo lường```{python}#| label: setup#| message: falseimport pandas as pdimport numpy as npimport matplotlib.pyplot as pltimport matplotlib.ticker as mtickerimport statsmodels.api as smimport statsmodels.formula.api as smffrom scipy import statsfrom typing import Optionalimport warningswarnings.filterwarnings("ignore")plt.rcParams.update({"figure.dpi": 150,"axes.spines.top": False,"axes.spines.right": False,"font.size": 11,})```Quản trị lợi nhuận là việc các nhà quản lý can thiệp có chủ đích vào quá trình lập báo cáo tài chính nhằm đạt được những kết quả phục vụ mục tiêu riêng, dù là để đạt dự báo của các nhà phân tích, kích hoạt ngưỡng thưởng, tránh vi phạm điều khoản vay nợ, hay tác động đến định giá cổ phiếu. Tuy khái niệm này khá trực quan, việc phát hiện nó một cách chặt chẽ lại là một trong những thách thức phương pháp luận lâu đời nhất của nghiên cứu kế toán thực nghiệm.Khó khăn này mang tính căn bản: nhà nghiên cứu chỉ quan sát được các khoản dồn tích *tổng cộng*, vốn gồm một thành phần hợp lý (phản ánh hoạt động kinh tế thực) và một thành phần tùy ý (phản ánh sự can thiệp của nhà quản lý). Tách hai thành phần này đòi hỏi một mô hình về mức dồn tích mà *lẽ ra* phải có nếu không có thao túng, mà tài liệu nghiên cứu gọi là **các khoản dồn tích không tùy ý (NDA)**. Phần dư bất kỳ, tức khoảng chênh giữa các khoản dồn tích quan sát được và dự báo của mô hình, sau đó được quy cho sự tùy ý của nhà quản lý. Do đó, chất lượng của phương pháp phát hiện phụ thuộc hoàn toàn vào chất lượng của mô hình này.Chương này xem xét ba cách tiếp cận nền tảng để đo lường quản trị lợi nhuận (tức là mô hình @healy1985effect, mô hình @jones1991earnings và mô hình Jones điều chỉnh của @dechow1995detecting) và đánh giá các tính chất thống kê của chúng bằng mô phỏng. Sau đó, chúng ta điều chỉnh phân tích cho bối cảnh thể chế của Việt Nam, nơi cơ cấu quản trị, chuẩn mực kế toán và chế độ thực thi khác biệt tạo ra cả những động cơ quản trị lợi nhuận đặc thù lẫn những thách thức đặc thù trong việc phát hiện nó.### Định nghĩa quản trị lợi nhuậnMột cách phân loại hữu ích phân biệt ba hình thức:1. **Quản trị lợi nhuận dựa trên dồn tích (AEM).** Nhà quản lý tận dụng quyền tùy ý trong khuôn khổ chuẩn mực kế toán để dịch chuyển thời điểm ghi nhận doanh thu hoặc chi phí. Ví dụ gồm ghi nhận doanh thu quá tích cực, trì hoãn việc ghi giảm giá trị tài sản, hoặc thao túng các ước tính dự phòng. Hình thức này không làm thay đổi dòng tiền cơ bản của doanh nghiệp.2. **Quản trị lợi nhuận thực (REM).** Nhà quản lý thực hiện các hành động kinh tế thực sự (ví dụ: sản xuất vượt mức để giảm chi phí đơn vị, cắt giảm chi phí R&D hoặc quảng cáo, giảm giá bán để đẩy nhanh doanh số) có hệ quả thực đối với dòng tiền [@roychowdhury2006earnings]. Những hành động này có thể cải thiện lợi nhuận kỳ hiện tại với cái giá là giá trị tương lai.3. **Dịch chuyển phân loại (classification shifting).** Nhà quản lý phân loại lại các khoản chi phí cốt lõi thành các khoản không thường xuyên để thổi phồng lợi nhuận cốt lõi mà không làm thay đổi lợi nhuận ròng cuối cùng. Hình thức này giữ nguyên cả tổng dồn tích lẫn dòng tiền.### Vì sao là Việt Nam?Môi trường thể chế của Việt Nam khuếch đại một số kênh liên quan đến nghiên cứu quản trị lợi nhuận:- **Động cơ của doanh nghiệp nhà nước (DNNN).** Các DNNN được cổ phần hóa một phần chịu hai áp lực: chỉ tiêu chính trị từ cổ đông nhà nước và kỳ vọng thị trường từ các nhà đầu tư thiểu số.- **Thực thi pháp luật.** Ủy ban Chứng khoán Nhà nước (SSC) của Việt Nam có nguồn lực hạn chế và lịch sử thể chế ngắn so với các cơ quan như SEC của Hoa Kỳ. Thực thi yếu làm giảm chi phí kỳ vọng của việc thao túng, có thể làm tăng mức độ phổ biến của nó [@leuz2003earnings].- **Chuẩn mực kế toán.** VAS (Chuẩn mực Kế toán Việt Nam) dựa trên các phiên bản IAS cũ hơn và chưa hội tụ hoàn toàn với IFRS. Một số quy định của VAS, như tiêu chí ghi nhận doanh thu dựa trên quy tắc và các phương pháp khấu hao được quy định sẵn, hạn chế một số hình thức tùy ý nhưng lại tạo ra những cơ hội có thể dự đoán cho các hình thức khác.- **Hành vi vượt ngưỡng chuẩn.** @burgstahler1997earnings ghi nhận sự gián đoạn quanh mức lợi nhuận bằng không và mức thay đổi lợi nhuận bằng không trong dữ liệu Hoa Kỳ. Thị trường Việt Nam, với mức độ tham gia cao của nhà đầu tư cá nhân và sự chú trọng vào lợi nhuận hiển thị, có thể cho thấy những mô thức tương tự hoặc thậm chí rõ nét hơn.## Các mô hình về dồn tích không tùy ý {#sec-models}### Ký hiệu và thiết lậpGọi $i$ là chỉ số doanh nghiệp và $t$ là chỉ số năm tài chính. Ta định nghĩa:| Ký hiệu | Định nghĩa ||-------------------------------|-----------------------------------------|| $TA_{i,t}$ | Tổng dồn tích (chia cho tài sản năm trước) || $NDA_{i,t}$ | Dồn tích không tùy ý (dự báo của mô hình) || $DA_{i,t}$ | Dồn tích tùy ý: $DA_{i,t} = TA_{i,t} - NDA_{i,t}$ || $A_{i,t}$ | Tổng tài sản || $\Delta Rev_{i,t}$ | Thay đổi doanh thu, chia cho $A_{i,t-1}$ || $\Delta Rec_{i,t}$ | Thay đổi các khoản phải thu ròng, chia cho $A_{i,t-1}$ || $PPE_{i,t}$ | Tài sản cố định hữu hình gộp (nguyên giá), chia cho $A_{i,t-1}$ || $PART_{i,t}$ | Biến chỉ báo bằng 1 cho năm kiểm định (năm sự kiện) |: Ký hiệu cho các mô hình quản trị lợi nhuận {#tbl-em-notation}Tổng dồn tích được tính theo phương pháp bảng cân đối kế toán:$$TA_{i,t} = \frac{(\Delta CA_{i,t} - \Delta Cash_{i,t}) - (\Delta CL_{i,t} - \Delta STD_{i,t}) - Dep_{i,t}}{A_{i,t-1}}$$ {#eq-total-accruals}trong đó $\Delta CA$ là thay đổi tài sản ngắn hạn, $\Delta Cash$ là thay đổi tiền mặt, $\Delta CL$ là thay đổi nợ ngắn hạn phải trả, $\Delta STD$ là thay đổi nợ vay ngắn hạn, và $Dep$ là chi phí khấu hao.### Năm mô hìnhChúng ta triển khai năm mô hình, mỗi mô hình ước lượng $NDA$ trong một cửa sổ ước lượng riêng của từng doanh nghiệp và tính $DA$ cho năm kiểm định như phần dư.**Mô hình 1**: @healy1985effect. Dồn tích không tùy ý bằng trung bình của tổng dồn tích trong kỳ ước lượng:$$NDA^{Healy}_{i,t} = \frac{1}{T} \sum_{s \in \text{est}} TA_{i,s}$$ {#eq-healy}Đây là chuẩn so sánh đơn giản nhất có thể. Hạn chế của nó rất rõ: nó coi *mọi* biến thiên theo thời gian của dồn tích là tùy ý, kể cả biến thiên do sự thay đổi môi trường kinh tế của doanh nghiệp gây ra.**Mô hình 2**: @deangelo1986accounting. Dồn tích không tùy ý bằng tổng dồn tích của kỳ trước:$$NDA^{DeAngelo}_{i,t} = TA_{i,t-1}$$ {#eq-deangelo}Điều này tương đương với giả định rằng thay đổi của tổng dồn tích hoàn toàn là tùy ý. Mô hình hoạt động tốt khi dồn tích tuân theo bước ngẫu nhiên, nhưng kém khi chúng có xu hướng hồi quy về trung bình hoặc có xu thế.**Mô hình 3**: @jones1991earnings. Mô hình này kiểm soát sự thay đổi của môi trường kinh tế doanh nghiệp bằng cách hồi quy dồn tích theo thay đổi doanh thu và mức tài sản cố định:$$TA_{i,t} = \alpha_1 \frac{1}{A_{i,t-1}} + \alpha_2 \Delta Rev_{i,t} + \alpha_3 PPE_{i,t} + \varepsilon_{i,t}$$ {#eq-jones}Các tham số $\hat{\alpha}_1, \hat{\alpha}_2, \hat{\alpha}_3$ được ước lượng trên dữ liệu kỳ ước lượng. Dồn tích không tùy ý của năm kiểm định là các giá trị khớp từ hồi quy này áp dụng cho các biến giải thích của năm kiểm định.Logic kinh tế là tăng trưởng doanh thu tạo ra các khoản dồn tích vốn lưu động hợp lý (khoản phải thu và hàng tồn kho cao hơn), còn tài sản cố định đại diện cho chi phí khấu hao không tùy ý. Hệ số chặn được chia cho tài sản năm trước thay vì đưa vào như một hằng số thông thường, theo @jones1991earnings.**Mô hình 4: Jones điều chỉnh** [@dechow1995detecting]. Điều chỉnh này hiệu chỉnh thay đổi doanh thu theo thay đổi khoản phải thu trong năm kiểm định, với tiền đề rằng tăng trưởng doanh thu bán chịu dễ bị thao túng hơn tăng trưởng doanh thu tiền mặt:$$NDA^{ModJones}_{i,t} = \hat{\alpha}_1 \frac{1}{A_{i,t-1}} + \hat{\alpha}_2 (\Delta Rev_{i,t} - \Delta Rec_{i,t}) + \hat{\alpha}_3 PPE_{i,t}$$ {#eq-mod-jones}Các hệ số vẫn được ước lượng từ mô hình Jones *chưa điều chỉnh* (@eq-jones) trên dữ liệu kỳ ước lượng, nhưng khoản phải thu chỉ được trừ khỏi doanh thu khi tính các giá trị khớp cho năm kiểm định.**Mô hình 5: Mô hình ngành.** Mô hình này giả định rằng thành phần chung của dồn tích trong một ngành phản ánh biến thiên không tùy ý:$$TA_{i,t} = \phi_0 + \phi_1 \cdot \widetilde{TA}_{j,t} + \eta_{i,t}$$ {#eq-industry}trong đó $\widetilde{TA}_{j,t}$ là trung vị tổng dồn tích của tất cả doanh nghiệp trong ngành $j$ (không kể doanh nghiệp $i$), được ước lượng trong kỳ ước lượng.### Triển khai```{python}#| label: calc-accruals-fn#| code-summary: "Function to compute total accruals from balance sheet data"def calc_accruals(df: pd.DataFrame) -> pd.DataFrame:""" Compute total accruals using the balance sheet approach. Expected columns: gvkey/ticker, year/fyear, at, act, che, lct, dlc, dp, sale, rect, ppegt """ firm_col ="ticker"if"ticker"in df.columns else"gvkey" year_col ="year"if"year"in df.columns else"fyear" df = df.sort_values([firm_col, year_col]).copy()# Lagged values and changes g = df.groupby(firm_col) df["lag_at"] = g["at"].shift(1) df["d_ca"] = g["act"].diff() df["d_cash"] = g["che"].diff() df["d_cl"] = g["lct"].diff() df["d_std"] = g["dlc"].diff() df["d_rev"] = g["sale"].diff() df["d_rec"] = g["rect"].diff()# Total accruals (raw) df["acc_raw"] = (df["d_ca"] - df["d_cash"] - df["d_cl"] + df["d_std"]) - df["dp"]return df``````{python}#| label: nda-models#| code-summary: "Implementations of five non-discretionary accrual models"def fit_healy(df: pd.DataFrame) -> pd.DataFrame:"""Healy (1985): NDA = mean accruals in estimation period.""" est_mean = df.loc[~df["part"], "acc_at"].mean() df = df.copy() df["nda_healy"] = est_mean df["da_healy"] = df["acc_at"] - df["nda_healy"]return dfdef fit_deangelo(df: pd.DataFrame) -> pd.DataFrame:"""DeAngelo (1986): NDA = prior-period total accruals.""" df = df.copy() df["nda_deangelo"] = df["acc_at"].shift(1) df["da_deangelo"] = df["acc_at"] - df["nda_deangelo"]return dfdef fit_jones(df: pd.DataFrame) -> pd.DataFrame:"""Jones (1991): Regression-based NDA controlling for revenue and PPE.""" df = df.copy() est = df[~df["part"]].dropna(subset=["acc_at", "one_at", "d_rev_at", "ppe_at"])iflen(est) <5: df["nda_jones"] = np.nan df["da_jones"] = np.nanreturn df y = est["acc_at"] X = est[["one_at", "d_rev_at", "ppe_at"]] model = sm.OLS(y, X).fit() pred_X = df[["one_at", "d_rev_at", "ppe_at"]].copy() df["nda_jones"] = model.predict(pred_X) df["da_jones"] = df["acc_at"] - df["nda_jones"]return dfdef fit_mod_jones(df: pd.DataFrame) -> pd.DataFrame:"""Modified Jones (Dechow et al., 1995): Adjust revenues for receivables.""" df = df.copy() est = df[~df["part"]].dropna(subset=["acc_at", "one_at", "d_rev_at", "ppe_at"])iflen(est) <5: df["nda_mod_jones"] = np.nan df["da_mod_jones"] = np.nanreturn df# Estimate on unadjusted Jones model y = est["acc_at"] X = est[["one_at", "d_rev_at", "ppe_at"]] model = sm.OLS(y, X).fit()# Predict using adjusted revenue (subtract receivable changes) pred_X = df[["one_at", "d_rev_alt_at", "ppe_at"]].copy() pred_X.columns = ["one_at", "d_rev_at", "ppe_at"] df["nda_mod_jones"] = model.predict(pred_X) df["da_mod_jones"] = df["acc_at"] - df["nda_mod_jones"]return dfdef fit_industry(df: pd.DataFrame) -> pd.DataFrame:"""Industry model: NDA = f(industry median accruals).""" df = df.copy() est = df[~df["part"]].dropna(subset=["acc_at", "acc_ind"])iflen(est) <5: df["nda_industry"] = np.nan df["da_industry"] = np.nanreturn df y = est["acc_at"] X = sm.add_constant(est["acc_ind"]) model = sm.OLS(y, X).fit() pred_X = sm.add_constant(df["acc_ind"]) df["nda_industry"] = model.predict(pred_X) df["da_industry"] = df["acc_at"] - df["nda_industry"]return df``````{python}#| label: get-nda-all#| code-summary: "Master function to apply all five models to a panel"def prepare_model_vars(df: pd.DataFrame) -> pd.DataFrame:"""Add scaled variables needed by the five NDA models.""" df = calc_accruals(df) firm_col ="ticker"if"ticker"in df.columns else"gvkey" df["sic2"] = df["sic"].astype(str).str[:2] df["acc_at"] = df["acc_raw"] / df["lag_at"] df["one_at"] =1.0/ df["lag_at"] df["d_rev_at"] = df["d_rev"] / df["lag_at"] df["d_rev_alt_at"] = (df["d_rev"] - df["d_rec"]) / df["lag_at"] df["ppe_at"] = df["ppegt"] / df["lag_at"]# Industry median accruals (estimation period only)# est_acc = df.loc[~df["part"], ["sic2", "acc_at"]].copy() est_acc = df.loc[df["part"] ==False, ["sic2", "acc_at"]].copy() ind_median = est_acc.groupby("sic2")["acc_at"].median().rename("acc_ind") df = df.merge(ind_median, on="sic2", how="left")return dfdef get_all_nda(df: pd.DataFrame) -> pd.DataFrame:""" Apply all five NDA models on a firm-by-firm basis. Returns a DataFrame with DA columns for each model. """ firm_col ="ticker"if"ticker"in df.columns else"gvkey" year_col ="year"if"year"in df.columns else"fyear" df_mod = prepare_model_vars(df) df_mod["part"] = df_mod["part"].astype(bool) results = []for firm, group in df_mod.groupby(firm_col): g = group.sort_values(year_col).copy() g = fit_healy(g) g = fit_deangelo(g) g = fit_jones(g) g = fit_mod_jones(g) g = fit_industry(g) results.append(g)return pd.concat(results, ignore_index=True)```### Hiệu chỉnh Salkever (1976)Một vấn đề phương pháp quan trọng nhưng ít được chú ý nảy sinh khi tính sai số chuẩn cho dồn tích tùy ý theo các mô hình dạng Jones. Trong quy trình hai giai đoạn tiêu chuẩn, nhà nghiên cứu trước hết ước lượng mô hình Jones trên kỳ ước lượng, rồi tính dồn tích tùy ý cho năm kiểm định như một *sai số dự báo*. Nhưng sai số chuẩn của sai số dự báo lớn hơn sai số chuẩn của phần dư khớp, vì nó bao hàm sự bất định của tham số từ ước lượng giai đoạn đầu. Bỏ qua sự khác biệt này dẫn đến sai số chuẩn bị đánh giá thấp và tỷ lệ bác bỏ bị thổi phồng, chính là vấn đề đã được ghi nhận trong @dechow1995detecting.@salkever1976use đưa ra một giải pháp thanh lịch: chạy một hồi quy duy nhất trên kỳ ước lượng và kỳ kiểm định *gộp lại*, có thêm biến giả $PART$ cho năm kiểm định. Hệ số của $PART$ bằng sai số dự báo (dồn tích tùy ý), và sai số chuẩn của nó phản ánh đúng sự bất định ước lượng của giai đoạn đầu.Với mô hình Jones, hồi quy một giai đoạn của Salkever là:$$TA_{i,t} = \alpha_1 \frac{1}{A_{i,t-1}} + \alpha_2 \Delta Rev_{i,t} + \alpha_3 PPE_{i,t} + \delta \cdot PART_{i,t} + u_{i,t}$$ {#eq-salkever}Hệ số $\hat{\delta}$ giống hệt về số học với ước lượng $DA$ hai giai đoạn, nhưng sai số chuẩn $\text{se}(\hat{\delta})$ của nó là sai số chuẩn đúng của sai số dự báo.```{python}#| label: salkever-demo#| code-summary: "Demonstration of the Salkever (1976) equivalence"def demonstrate_salkever(df_firm: pd.DataFrame) -> pd.DataFrame:""" For a single firm, show that the two-stage Jones DA equals the Salkever one-stage coefficient on PART. """ df = prepare_model_vars(df_firm) needed = ["acc_at", "one_at", "d_rev_at", "ppe_at", "part"] df = df.dropna(subset=needed).copy()# ── Two-stage approach ── est = df[~df["part"]] y_est = est["acc_at"] X_est = est[["one_at", "d_rev_at", "ppe_at"]] fm_stage1 = sm.OLS(y_est, X_est).fit() df["nda_two_stage"] = fm_stage1.predict(df[["one_at", "d_rev_at", "ppe_at"]]) df["da_two_stage"] = df["acc_at"] - df["nda_two_stage"]# Test-year DA from two-stage da_two_stage = df.loc[df["part"], "da_two_stage"].values# ── Salkever one-stage ── df["part_float"] = df["part"].astype(float) y_full = df["acc_at"] X_full = df[["one_at", "d_rev_at", "ppe_at", "part_float"]] fm_salkever = sm.OLS(y_full, X_full).fit() da_salkever = fm_salkever.params["part_float"] se_two_stage_wrong = np.nan # two-stage doesn't give correct SE se_salkever = fm_salkever.bse["part_float"]return pd.DataFrame({"Method": ["Two-stage Jones", "Salkever one-stage"],"DA estimate": [da_two_stage[0] iflen(da_two_stage) else np.nan, da_salkever],"Correct SE": ["Not available", f"{se_salkever:.6f}"],"t-statistic": ["Biased", f"{fm_salkever.tvalues['part_float']:.4f}"], })```## Sai lầm loại I dưới giả thuyết không {#sec-type1}### Thiết kế thực nghiệmĐể đánh giá liệu năm mô hình có cho ra các thống kê kiểm định được hiệu chỉnh tốt hay không, chúng ta tiến hành một thực nghiệm mô phỏng song song với Bảng 2 của @dechow1995detecting. Quy trình như sau:1. Tạo một bảng dữ liệu (panel) gồm $N$ doanh nghiệp, mỗi doanh nghiệp có $T$ năm dữ liệu báo cáo tài chính.2. Với mỗi doanh nghiệp, chọn ngẫu nhiên một năm làm năm kiểm định ($PART = 1$). Theo cách xây dựng, *không có quản trị lợi nhuận nào xảy ra* trong năm này.3. Ước lượng dồn tích tùy ý bằng từng mô hình trong năm mô hình.4. Hồi quy $DA$ theo $PART$ cho từng doanh nghiệp và ghi nhận liệu giả thuyết không $H_0: \delta = 0$ có bị bác bỏ ở mức ý nghĩa 5% và 1% hay không.5. Tính tỷ lệ bác bỏ trên toàn bộ $N$ doanh nghiệp.Nếu mô hình được xác định đúng, tỷ lệ bác bỏ phải bằng mức ý nghĩa danh nghĩa của kiểm định (5% hoặc 1%). Việc bác bỏ quá mức một cách hệ thống cho thấy mô hình tạo ra các thống kê kiểm định chệch, một khiếm khuyết nghiêm trọng đối với nghiên cứu dựa vào các thước đo này để đưa ra suy luận nhân quả.### Tạo dữ liệuChúng ta tạo dữ liệu panel tổng hợp giữ được các tính chất chính theo mặt cắt ngang và chuỗi thời gian của các doanh nghiệp niêm yết Việt Nam, đồng thời cho phép ta biết chắc chắn rằng không có thao túng nào tồn tại.```{python}#| label: gen-panel#| code-summary: "Generate synthetic Vietnamese panel data for Type I error analysis"def generate_em_panel( n_firms: int=500, n_years: int=15, seed: int=2024,) -> pd.DataFrame:""" Generate a synthetic panel of Vietnamese-style financial data. No earnings management is present by construction. The data generation process captures: - AR(1) revenue process - Accruals driven by revenue growth and PPE levels - Industry-level common shocks - SOE/non-SOE heterogeneity """ rng = np.random.default_rng(seed) industries = [10, 20, 25, 41, 46, 47, 52, 62, 64, 68] records = []for i inrange(n_firms):# Firm characteristics sic = rng.choice(industries) is_soe =int(rng.random() <0.30) base_assets = rng.lognormal(mean=12, sigma=1.5) # VND billions growth_rate = rng.normal(0.08, 0.04)# Jones model parameters (firm-specific true DGP) true_alpha1 = rng.normal(0, 0.02) true_alpha2 = rng.normal(0.06, 0.03) # revenue-accrual sensitivity true_alpha3 = rng.normal(-0.04, 0.02) # depreciation effect at_prev = base_assets sale_prev = base_assets * rng.uniform(0.5, 1.5) rect_prev = sale_prev * rng.uniform(0.05, 0.25)for t inrange(n_years): year =2009+ t# Evolve fundamentals at = at_prev * (1+ growth_rate + rng.normal(0, 0.05)) sale = sale_prev * (1+ rng.normal(0.06, 0.08)) rect = sale * rng.uniform(0.05, 0.25) ppegt = at * rng.uniform(0.3, 0.7)# Generate accruals from true Jones DGP + noise d_rev = sale - sale_prev one_at =1.0/ at_prev d_rev_at = d_rev / at_prev ppe_at = ppegt / at_prev acc_at = (true_alpha1 * one_at + true_alpha2 * d_rev_at + true_alpha3 * ppe_at+ rng.normal(0, 0.03)) acc_raw = acc_at * at_prev# Reverse-engineer balance sheet items consistent with accruals dp = ppegt * rng.uniform(0.05, 0.12) d_cl = rng.normal(0, at *0.02) d_std = rng.normal(0, at *0.01) d_cash = rng.normal(0, at *0.02) d_ca = acc_raw + dp + d_cl - d_std + d_cash act = at * rng.uniform(0.3, 0.6) che = act * rng.uniform(0.05, 0.2) lct = at * rng.uniform(0.15, 0.35) dlc = lct * rng.uniform(0.1, 0.4) ni = sale * rng.uniform(0.03, 0.12) ib = ni records.append({"ticker": f"VN{i:04d}","fyear": year,"at": at,"act": act,"che": che,"lct": lct,"dlc": dlc,"dp": dp,"sale": sale,"rect": rect,"ppegt": ppegt,"ni": ni,"ib": ib,"sic": sic,"is_soe": is_soe, }) at_prev = at sale_prev = sale rect_prev = rect df = pd.DataFrame(records)return dfpanel_raw = generate_em_panel(n_firms=500, n_years=15, seed=2024)print(f"Panel: {panel_raw.shape[0]:,} firm-years, "f"{panel_raw['ticker'].nunique()} firms")```### Xây dựng mẫuChúng ta xây dựng một mẫu gồm 500 doanh nghiệp, mỗi doanh nghiệp có một năm kiểm định được chọn ngẫu nhiên, mô phỏng thiết kế của @dechow1995detecting.```{python}#| label: sample-construction#| code-summary: "Construct analysis sample with random test-year assignment"def construct_sample( df: pd.DataFrame, n_sample: int=500, min_est_years: int=10, seed: int=42, selection_filter: Optional[callable] =None,) -> pd.DataFrame:""" For each firm, randomly assign one year as the test year (part=True). Require at least min_est_years of estimation data. """ rng = np.random.default_rng(seed) firm_col ="ticker" year_col ="fyear"# Compute accruals and filter for data availability df = calc_accruals(df) required = ["acc_raw", "lag_at", "d_rev", "d_rec", "ppegt"] df = df.dropna(subset=required) df = df[df["lag_at"] >0]# Require minimum years firm_counts = df.groupby(firm_col)[year_col].count() eligible = firm_counts[firm_counts >= (min_est_years +1)].index df = df[df[firm_col].isin(eligible)]if selection_filter isnotNone: df = selection_filter(df)# Sample n_sample firms firms = df[firm_col].unique()iflen(firms) > n_sample: firms = rng.choice(firms, n_sample, replace=False) df = df[df[firm_col].isin(firms)].copy()# For each firm, randomly pick one test year (not the first year) parts = []for firm, group in df.groupby(firm_col): years = group[year_col].sort_values().valuesiflen(years) <2:continue test_year = rng.choice(years[1:]) parts.append({firm_col: firm, year_col: test_year, "part": True}) part_df = pd.DataFrame(parts) df = df.merge(part_df, on=[firm_col, year_col], how="left") df["part"] = df["part"].fillna(False) df["part"] = df["part"].astype(bool)return dfsample_1 = construct_sample(panel_raw, n_sample=500, seed=2024)print(f"Sample 1: {sample_1.shape[0]:,} firm-years, "f"{sample_1['ticker'].nunique()} firms, "f"{sample_1['part'].sum()} test years")```### Ước lượng dồn tích tùy ý```{python}#| label: estimate-da#| code-summary: "Apply all five models to Sample 1"da_results = get_all_nda(sample_1)# Verify: peek at test-year DA across modelsda_cols = ["da_healy", "da_deangelo", "da_jones", "da_mod_jones", "da_industry"]test_da = da_results[da_results["part"]][da_cols]print("Test-year discretionary accruals (first 5 firms):")test_da.head().round(4)```### Hồi quy cấp doanh nghiệp và tỷ lệ bác bỏVới mỗi doanh nghiệp và mỗi mô hình, chúng ta hồi quy $DA$ theo $PART$ và ghi nhận liệu giả thuyết không về dồn tích tùy ý bằng không trong năm kiểm định có bị bác bỏ hay không.```{python}#| label: type1-regressions#| code-summary: "Compute firm-specific t-statistics and rejection rates"def firm_regressions(df: pd.DataFrame, models: list[str]) -> pd.DataFrame:""" For each firm and model, regress DA on PART. Return coefficients, std errors, t-stats, and rejection indicators. """ firm_col ="ticker"if"ticker"in df.columns else"gvkey" records = []for firm, group in df.groupby(firm_col):for model in models: da_col =f"da_{model}" g = group.dropna(subset=[da_col]).copy() g["part_float"] = g["part"].astype(float)iflen(g) <5or g["part"].sum() ==0:continuetry: fm = sm.OLS( g[da_col], sm.add_constant(g["part_float"]) ).fit() coef = fm.params["part_float"] se = fm.bse["part_float"] t_stat = fm.tvalues["part_float"] df_resid = fm.df_resid# One-sided p-values p_neg = stats.t.cdf(t_stat, df_resid) p_pos =1- p_neg records.append({ firm_col: firm,"model": model,"coef": coef,"se": se,"t_stat": t_stat,"neg_p01": p_neg <0.01,"neg_p05": p_neg <0.05,"pos_p01": p_pos <0.01,"pos_p05": p_pos <0.05, })exceptException:continuereturn pd.DataFrame(records)models = ["healy", "deangelo", "jones", "mod_jones", "industry"]reg_results = firm_regressions(da_results, models)```### Kết quả@tbl-type1-coefs báo cáo phân phối của các hệ số ước lượng trên $PART$ qua các doanh nghiệp. Dưới giả thuyết không là không có thao túng, ta kỳ vọng hệ số trung bình xấp xỉ bằng không.```{python}#| label: tbl-type1-coefs#| tbl-cap: "Phân phối các ước lượng dồn tích tùy ý cấp doanh nghiệp (hệ số trên PART) dưới giả thuyết không là không có quản trị lợi nhuận. Cả năm mô hình đều cho ước lượng trung bình gần bằng không, như kỳ vọng."coef_stats = ( reg_results .groupby("model")["coef"] .agg(["mean", "std", lambda x: x.quantile(0.25),"median", lambda x: x.quantile(0.75)]))coef_stats.columns = ["Mean", "Std Dev", "Q1", "Median", "Q3"]coef_stats.index.name ="Model"coef_stats.round(4)```@tbl-type1-rejection báo cáo tỷ lệ bác bỏ. So sánh then chốt là liệu các tỷ lệ này có xấp xỉ mức ý nghĩa danh nghĩa của kiểm định hay không.```{python}#| label: tbl-type1-rejection#| tbl-cap: "Tỷ lệ sai lầm loại I của các kiểm định một phía về quản trị lợi nhuận dưới giả thuyết không. Tỷ lệ vượt mức ý nghĩa danh nghĩa (5% hoặc 1%) cho thấy mô hình bác bỏ quá mức, một mối quan ngại đáng kể đối với các mô hình Jones và Jones điều chỉnh."rejection_rates = ( reg_results .groupby("model")[["neg_p01", "neg_p05", "pos_p01", "pos_p05"]] .mean() .round(4))rejection_rates.columns = ["Neg (1%)", "Neg (5%)", "Pos (1%)", "Pos (5%)"]rejection_rates.index.name ="Model"rejection_rates```### Kiểm định nhị thức cho sai lệch mức ý nghĩa thực tế của kiểm địnhChúng ta kiểm định chính thức liệu các tỷ lệ bác bỏ quan sát được có khác mức ý nghĩa danh nghĩa hay không bằng kiểm định nhị thức hai phía. Giá trị $p$ nhỏ cho thấy thống kê kiểm định bị hiệu chỉnh sai đáng kể.```{python}#| label: tbl-binom-test#| tbl-cap: "Giá trị p của kiểm định nhị thức về việc tỷ lệ bác bỏ có bằng mức ý nghĩa danh nghĩa hay không. Giá trị nhỏ (ví dụ < 0.05) cho thấy mức ý nghĩa thực tế lệch khỏi mức danh nghĩa một cách có ý nghĩa thống kê."def binom_test_rate(series: pd.Series, nominal: float) ->float:"""Two-sided binomial test for rejection rate = nominal.""" x = series.dropna() k =int(x.sum()) n =len(x)if n ==0:return np.nanreturn stats.binomtest(k, n, nominal, alternative="two-sided").pvaluebinom_results = {}for model, group in reg_results.groupby("model"): binom_results[model] = {"Neg (1%)": binom_test_rate(group["neg_p01"], 0.01),"Neg (5%)": binom_test_rate(group["neg_p05"], 0.05),"Pos (1%)": binom_test_rate(group["pos_p01"], 0.01),"Pos (5%)": binom_test_rate(group["pos_p05"], 0.05), }binom_df = pd.DataFrame(binom_results).T.round(4)binom_df.index.name ="Model"binom_df```::: callout-warning## Diễn giải việc bác bỏ quá mứcNếu các mô hình Jones và Jones điều chỉnh cho thấy tỷ lệ bác bỏ cao hơn 5% một cách có ý nghĩa, điều này báo hiệu rằng quy trình hai giai đoạn tiêu chuẩn tạo ra các thống kê kiểm định phản bảo thủ (anti-conservative). Hiệu chỉnh của @salkever1976use giải quyết vấn đề này bằng cách tính sai số chuẩn phản ánh sự bất định ước lượng của giai đoạn đầu. Trong nghiên cứu thực tế về các doanh nghiệp Việt Nam, nơi chuỗi quan sát theo từng doanh nghiệp thường ngắn (10–15 năm lịch sử niêm yết), hiệu chỉnh này đặc biệt quan trọng vì phương sai sai số dự báo chiếm tỷ trọng lớn hơn trong phương sai phần dư khi số quan sát kỳ ước lượng ít hơn.:::## Các doanh nghiệp có kết quả hoạt động cực đoan {#sec-extreme}Một điểm yếu quen thuộc của các mô hình dựa trên dồn tích là hiệu quả kém khi các doanh nghiệp kiểm định trải qua kết quả kinh tế cực đoan. @dechow1995detecting ghi nhận rằng cả năm mô hình đều bác bỏ quá mức giả thuyết không khi các quan sát doanh nghiệp–năm kiểm định được lấy từ phần đuôi của phân phối lợi nhuận hoặc dòng tiền. @kothari2005performance sau đó đề xuất "ghép cặp theo hiệu quả hoạt động" (performance matching) như một biện pháp khắc phục một phần.Trực giác của vấn đề khá đơn giản: mô hình Jones giả định một quan hệ tuyến tính, đối xứng giữa thay đổi doanh thu và dồn tích. Nhưng các doanh nghiệp trải qua tăng trưởng hoặc suy giảm cực đoan tạo ra các khoản dồn tích lệch phi tuyến khỏi dự báo của mô hình, ngay cả khi không có bất kỳ thao túng nào. Tính phi tuyến này bị quy nhầm cho dồn tích tùy ý.### Xây dựng các mẫu có kết quả hoạt động cực đoan```{python}#| label: extreme-sample#| code-summary: "Construct samples from top and bottom earnings deciles"def add_earnings_deciles(df: pd.DataFrame) -> pd.DataFrame:"""Compute firm-year earnings (scaled) and assign to deciles.""" firm_col ="ticker"if"ticker"in df.columns else"gvkey" df = df.copy() g = df.groupby(firm_col) df["lag_at_earn"] = g["at"].shift(1) df["earn"] = df["ib"] / df["lag_at_earn"] df["earn_decile"] = pd.qcut( df["earn"], 10, labels=False, duplicates="drop" ) +1return dfpanel_with_earn = add_earnings_deciles(panel_raw)# High-earners sample (top decile)def filter_high_earn(df): df = add_earnings_deciles(df)return df[df["earn_decile"] ==10]# Low-earners sample (bottom decile)def filter_low_earn(df): df = add_earnings_deciles(df)return df[df["earn_decile"] ==1]sample_high = construct_sample( panel_raw, n_sample=300, seed=100, selection_filter=filter_high_earn)sample_low = construct_sample( panel_raw, n_sample=300, seed=200, selection_filter=filter_low_earn)print(f"High-earnings sample: {sample_high['ticker'].nunique()} firms")print(f"Low-earnings sample: {sample_low['ticker'].nunique()} firms")``````{python}#| label: tbl-extreme-rejection#| tbl-cap: "Tỷ lệ sai lầm loại I (một phía, 5%) khi các quan sát doanh nghiệp–năm kiểm định được lấy từ các thập phân vị lợi nhuận cực đoan. Việc bác bỏ quá mức là điều được kỳ vọng vì các mô hình dồn tích quy nhầm biến thiên dồn tích do kết quả hoạt động cho sự tùy ý của nhà quản lý."extreme_results = {}for label, sample_df in [("High earners", sample_high), ("Low earners", sample_low)]: da = get_all_nda(sample_df) regs = firm_regressions(da, models) rates = regs.groupby("model")[["neg_p05", "pos_p05"]].mean().round(4) rates.columns = [f"{label} Neg(5%)", f"{label} Pos(5%)"] extreme_results[label] = ratesif extreme_results: extreme_df = pd.concat(extreme_results.values(), axis=1) extreme_df.index.name ="Model" extreme_df```### Ghép cặp theo hiệu quả hoạt động@kothari2005performance đề xuất điều chỉnh dồn tích tùy ý bằng cách trừ đi DA của một doanh nghiệp được ghép cặp theo hiệu quả hoạt động (cùng ngành và có ROA tương tự). Cách này loại bỏ thành phần hệ thống của dồn tích có tương quan với hiệu quả hoạt động. Dồn tích tùy ý sau ghép cặp là:$$DA^{PM}_{i,t} = DA_{i,t} - DA_{i^*,t}$$ {#eq-performance-match}trong đó $i^*$ là doanh nghiệp đối chứng được ghép cặp. Cách tiếp cận này đặc biệt phù hợp với Việt Nam, nơi mặt cắt ngang các doanh nghiệp niêm yết gồm nhiều doanh nghiệp tăng trưởng cao bên cạnh các DNNN trì trệ, một sự không đồng nhất về hiệu quả hoạt động mà các mô hình tiêu chuẩn có thể mô tả sai.## Phân tích sức mạnh kiểm định {#sec-power}### Đưa quản trị lợi nhuận nhân tạo vào dữ liệuMột mô hình không bao giờ bác bỏ là vô dụng dù tỷ lệ sai lầm loại I của nó hoàn hảo. Chúng ta cần đánh giá **sức mạnh kiểm định (power)**: xác suất phát hiện thao túng khi nó thực sự tồn tại. Theo @dechow1995detecting, chúng ta đưa vào báo cáo tài chính của năm kiểm định một lượng thao túng nhân tạo đã biết và đo tỷ lệ phát hiện.Chúng ta xét ba hình thức thao túng ở các mức độ khác nhau:1. **Thao túng chi phí.** Giảm nợ ngắn hạn phải trả đi một lượng bằng mức thao túng (ví dụ: trì hoãn ghi nhận chi phí phải trả): $$LCT'_{i,t} = LCT_{i,t} - \lambda \cdot A_{i,t-1}$$2. **Thao túng doanh thu.** Tăng doanh thu và khoản phải thu một lượng bằng mức thao túng (ví dụ: ghi nhận doanh thu sớm hoặc nhồi hàng vào kênh phân phối): $$Sale'_{i,t} = Sale_{i,t} + \lambda \cdot A_{i,t-1}, \quad Rect'_{i,t} = Rect_{i,t} + \lambda \cdot A_{i,t-1}$$3. **Thao túng biên lợi nhuận.** Tăng doanh thu một lượng gộp cần thiết để thổi phồng lợi nhuận ròng thêm $\lambda \cdot A_{i,t-1}$, đồng thời tăng cả khoản phải thu và nợ ngắn hạn phải trả theo tỷ lệ.Tham số $\lambda$ biểu thị mức thao túng dưới dạng tỷ lệ của tổng tài sản năm trước, dao động từ 0% đến 50%.```{python}#| label: manipulate-fn#| code-summary: "Function to introduce artificial manipulation"def manipulate( df: pd.DataFrame, level: float=0.0, manip_type: str="expense",) -> pd.DataFrame:""" Introduce artificial earnings management of a given type and level into test-year (part=True) observations. Parameters ---------- df : DataFrame with 'part' indicator and required financial variables. level : Manipulation as fraction of lagged total assets. manip_type : One of 'expense', 'revenue', 'margin'. """ firm_col ="ticker"if"ticker"in df.columns else"gvkey" year_col ="fyear"if"fyear"in df.columns else"year" df = df.sort_values([firm_col, year_col]).copy() g = df.groupby(firm_col) lag_at = g["at"].shift(1) manip_amt = lag_at * levelif manip_type =="expense":# Decrease current liabilities in test year df.loc[df["part"], "lct"] -= manip_amt[df["part"]]elif manip_type =="revenue":# Increase sales and receivables in test year df.loc[df["part"], "sale"] += manip_amt[df["part"]] df.loc[df["part"], "rect"] += manip_amt[df["part"]] df.loc[df["part"], "act"] += manip_amt[df["part"]]# Reverse in following year next_part = g["part"].shift(1).fillna(False) df.loc[next_part, "sale"] -= manip_amt[next_part]elif manip_type =="margin":# Compute net income ratio for scaling est_mask =~df["part"] ni_ratio = g.apply(lambda x: (x.loc[~x["part"], "ni"] / x.loc[~x["part"], "sale"]).median() ) df["_ni_ratio"] = df[firm_col].map(ni_ratio) gross_amt = np.where( df["_ni_ratio"] >0, manip_amt / df["_ni_ratio"], 0 ) df.loc[df["part"], "sale"] += gross_amt[df["part"]] df.loc[df["part"], "rect"] += gross_amt[df["part"]] df.loc[df["part"], "act"] += gross_amt[df["part"]] net_effect = gross_amt - manip_amt df.loc[df["part"], "lct"] += net_effect[df["part"]] df.drop(columns=["_ni_ratio"], inplace=True)return df``````{python}#| label: power-analysis#| eval: false#| code-summary: "Power analysis across manipulation levels and types"levels = [0.0, 0.05, 0.10, 0.20, 0.30, 0.50]manip_types = ["expense", "revenue", "margin"]power_records = []for level in levels:for mtype in manip_types:# Copy base sample and introduce manipulation manip_sample = sample_1.copy()if level >0: manip_sample = manipulate(manip_sample, level=level, manip_type=mtype)# Estimate DA and run tests da = get_all_nda(manip_sample) regs = firm_regressions(da, models)# Power = positive one-sided rejection rate at 5% power = regs.groupby("model")["pos_p05"].mean()for model_name, pwr in power.items(): power_records.append({"level": level,"type": mtype,"model": model_name,"power": pwr, })power_df = pd.DataFrame(power_records)``````{python}#| label: power-analysis-parallel#| code-summary: "Power analysis across manipulation levels and types"levels = [0.0, 0.05, 0.10, 0.20, 0.30, 0.50]manip_types = ["expense", "revenue", "margin"]from joblib import Parallel, delayedfrom itertools import productdef _run_one(level, mtype, base_sample, models): manip_sample = base_sample.copy()if level >0: manip_sample = manipulate(manip_sample, level=level, manip_type=mtype) da = get_all_nda(manip_sample) regs = firm_regressions(da, models) power = regs.groupby("model")["pos_p05"].mean()return [ {"level": level, "type": mtype, "model": m, "power": p}for m, p in power.items() ]# Skip redundant level=0 runs (all manip_types identical when level=0)combos = [(0.0, "expense")] + [ (l, m) for l in levels if l >0for m in manip_types]results = Parallel(n_jobs=-1, verbose=1)( delayed(_run_one)(lvl, mt, sample_1, models)for lvl, mt in combos)# Expand level=0 result across all manip_typesflat = []for (lvl, mt), batch inzip(combos, results):if lvl ==0:for mtype in manip_types: flat.extend([{**r, "type": mtype} for r in batch])else: flat.extend(batch)power_df = pd.DataFrame(flat)```### Các hàm sức mạnh kiểm định@fig-power vẽ các hàm sức mạnh kiểm định ước lượng được. Các câu hỏi then chốt là: (i) mô hình nào có sức mạnh cao nhất với một mức và loại thao túng cho trước, và (ii) ở quy mô nào thì thao túng trở nên có thể phát hiện một cách đáng tin cậy?```{python}#| label: fig-power#| fig-cap: "Các hàm sức mạnh kiểm định của năm mô hình phát hiện quản trị lợi nhuận qua ba loại thao túng. Sức mạnh tăng theo quy mô thao túng nhưng vẫn thấp ở các mức hợp lý về mặt kinh tế (< 10% tài sản), cho thấy khó khăn căn bản của việc phát hiện quản trị lợi nhuận."fig, axes = plt.subplots(1, 3, figsize=(14, 5), sharey=True)model_colors = {"healy": "#2196F3","deangelo": "#FF9800","jones": "#4CAF50","mod_jones": "#E91E63","industry": "#9C27B0",}for idx, mtype inenumerate(manip_types): ax = axes[idx] subset = power_df[power_df["type"] == mtype]for model_name in models: m_data = subset[subset["model"] == model_name].sort_values("level") ax.plot( m_data["level"] *100, m_data["power"], marker="o", markersize=4, label=model_name.replace("_", " ").title(), color=model_colors[model_name], linewidth=1.5, ) ax.set_title(mtype.title(), fontweight="bold") ax.set_xlabel("Manipulation (% of assets)") ax.set_ylim(-0.02, 1.02) ax.yaxis.set_major_formatter(mticker.PercentFormatter(xmax=1)) ax.axhline(0.05, color="grey", linestyle="--", linewidth=0.7, label="5% size")axes[0].set_ylabel("Rejection Rate (Power)")axes[2].legend(fontsize=8, loc="center left", bbox_to_anchor=(1.02, 0.5))plt.tight_layout()plt.show()```### Thống kê tóm tắt@tbl-power-summary báo cáo sức mạnh kiểm định tại một số mức thao túng chọn lọc cho các mô hình Jones và Jones điều chỉnh, là hai mô hình được dùng phổ biến nhất trong nghiên cứu ứng dụng.```{python}#| label: tbl-power-summary#| tbl-cap: "Sức mạnh kiểm định của các mô hình Jones và Jones điều chỉnh tại một số mức thao túng chọn lọc. Ngay cả ở mức 10% tài sản, một lượng thao túng lớn, tỷ lệ phát hiện vẫn thấp hơn nhiều so với 50% với hầu hết các loại thao túng, nhấn mạnh sức mạnh thống kê thấp của các kiểm định tiêu chuẩn."power_summary = ( power_df[power_df["model"].isin(["jones", "mod_jones"])] .pivot_table(index=["model", "level"], columns="type", values="power") .round(3))power_summary.index.names = ["Model", "Level (% assets)"]power_summary```::: callout-important## Hàm ý cho nghiên cứu về Việt NamPhân tích sức mạnh kiểm định có những hàm ý rõ rệt đối với nghiên cứu quản trị lợi nhuận ở Việt Nam. Một doanh nghiệp niêm yết Việt Nam điển hình đã niêm yết 10–15 năm, cung cấp ít quan sát kỳ ước lượng hơn nhiều so với bối cảnh Hoa Kỳ, nơi @dechow1995detecting có hàng thập kỷ dữ liệu Compustat. Cửa sổ ước lượng ngắn hơn làm tăng sự bất định tham số trong mô hình Jones, làm giảm thêm sức mạnh kiểm định. Kết hợp với dữ liệu tài chính nhiễu hơn vốn phổ biến ở các thị trường mới nổi, nhà nghiên cứu nên diễn giải việc không bác bỏ giả thuyết không là không mang thông tin, thay vì là bằng chứng cho thấy báo cáo tài chính trong sạch.:::## Bối cảnh thể chế Việt Nam {#sec-vietnam}### Các kênh quản trị lợi nhuậnMột số đặc điểm của môi trường thể chế Việt Nam tạo ra những động cơ và cơ hội quản trị lợi nhuận đặc thù:**Thao túng do thuế.** Thuế suất thuế thu nhập doanh nghiệp (CIT) của Việt Nam đã giảm từ 28% (trước năm 2009) xuống 20% (từ năm 2016 trở đi), kèm các mức ưu đãi cho doanh nghiệp trong Khu kinh tế đặc biệt và các ngành công nghệ cao. Sự gắn kết chặt chẽ giữa kế toán VAS và kế toán thuế tạo động cơ quản trị lợi nhuận theo hướng giảm để giảm nghĩa vụ thuế, một mô thức đã được ghi nhận ở các nền kinh tế đang phát triển có truyền thống kế toán theo luật thành văn [@ball2003incentives].**Động cơ IPO và phát hành thêm cổ phiếu (SEO).** Việt Nam đã trải qua nhiều làn sóng cổ phần hóa DNNN (tư nhân hóa một phần). Các nhà quản lý có động cơ thổi phồng lợi nhuận trước các đợt chào bán cổ phiếu để tối đa hóa số tiền thu được. SSC yêu cầu các ngưỡng lợi nhuận tối thiểu để đủ điều kiện niêm yết, tạo ra động cơ mạnh quanh các ngưỡng quy định này, vốn là bối cảnh tự nhiên cho phân tích gián đoạn của @burgstahler1997earnings. Sự tùy ý kế toán quanh các đợt IPO không chỉ giới hạn ở lợi nhuận báo cáo: nó mở rộng sang việc định giá thù lao bằng cổ phần trước IPO. @badertscher2026cheap nghiên cứu "cheap stock" (cổ phiếu giá rẻ)—thù lao bằng cổ phần được cấp trước IPO với giá thực hiện thấp hơn nhiều so với giá chào bán cuối cùng (trong mẫu Hoa Kỳ của họ, giá IPO cao hơn giá thực hiện quyền chọn trước IPO hơn năm lần)—và chỉ ra rằng việc định giá thấp cổ phiếu trước IPO cho phép doanh nghiệp báo cáo chi phí thù lao nhỏ hơn trong khi chuyển giao một lượng giá trị đáng kể cho nội bộ. Quan trọng hơn, họ ghi nhận rằng cheap stock có những hệ quả thực: các doanh nghiệp sử dụng nó có thù lao CEO cao hơn (tính theo giá IPO), đầu tư sau IPO thấp hơn, lợi nhuận cổ phiếu sau IPO yếu hơn và mức định giá thấp khi IPO lớn hơn. Cơ chế này rất phù hợp với các đợt IPO cổ phần hóa ở Việt Nam, nơi việc phân bổ cổ phần cho nội bộ ở mức giá ưu đãi trước khi niêm yết là mối quan ngại quản trị công ty lặp đi lặp lại và nơi việc định giá quyền chọn cổ phần của nhân viên và ban quản lý trước khi niêm yết còn mang tính tùy ý đáng kể.**Quản trị lợi nhuận thực trong ngành sản xuất.** @roychowdhury2006earnings xác định sản xuất vượt mức, cắt giảm chi tiêu tùy ý và thao túng doanh số là ba kênh chính của quản trị lợi nhuận thực. Ngành sản xuất lớn của Việt Nam (dệt may, lắp ráp điện tử, chế biến thực phẩm) tạo nhiều dư địa cho REM dựa trên sản xuất vượt mức, trong đó chi phí đơn vị được giảm bằng cách phân bổ chi phí cố định chung lên các đợt sản xuất lớn hơn.**Related-party transactions.** Transactions with affiliated entities are a well-documented channel for earnings manipulation in Asian markets. Vietnamese conglomerates (*tập đoàn*) often feature complex cross-ownership structures where transfer pricing between subsidiaries can shift profits across reporting entities.### Kiểm định phân phối lợi nhuận@burgstahler1997earnings quan sát thấy một sự gián đoạn đáng chú ý trong phân phối lợi nhuận báo cáo quanh mức không: số doanh nghiệp báo cáo lợi nhuận dương nhỏ nhiều hơn hẳn số báo cáo khoản lỗ nhỏ, so với những gì một phân phối trơn sẽ dự báo. Mô thức này được diễn giải là bằng chứng cho thấy các doanh nghiệp quản trị lợi nhuận để tránh báo cáo lỗ.Chúng ta áp dụng kiểm định này cho dữ liệu mô phỏng kiểu Việt Nam để minh họa phương pháp.```{python}#| label: fig-earnings-distribution#| fig-cap: "Phân phối lợi nhuận đã chia theo quy mô quanh mức không. Một sự gián đoạn, tức mật độ dư ngay trên mức không và thiếu hụt ngay dưới mức không, sẽ gợi ý hành vi vượt ngưỡng chuẩn. Đường đứt nét màu đỏ đánh dấu ngưỡng không."# Generate earnings for a larger sample with benchmark-beating behaviorrng_dist = np.random.default_rng(2024)n_firms_dist =2000n_years_dist =10earnings = []for i inrange(n_firms_dist): base_earn = rng_dist.normal(0.06, 0.08)for t inrange(n_years_dist): e = base_earn + rng_dist.normal(0, 0.04)# Simulate benchmark-beating: firms near zero bump earnings upif-0.01< e <0.005: e += rng_dist.uniform(0.005, 0.015) * (rng_dist.random() <0.6) earnings.append(e)earn_array = np.array(earnings)fig, ax = plt.subplots(figsize=(8, 5))bins = np.arange(-0.30, 0.35, 0.01)ax.hist(earn_array, bins=bins, color="steelblue", edgecolor="white", alpha=0.85, density=True)ax.axvline(0, color="firebrick", linestyle="--", linewidth=1.5, label="Zero threshold")ax.set_xlabel("Earnings / Total Assets")ax.set_ylabel("Density")ax.set_title("Earnings Distribution Around Zero")ax.legend()plt.tight_layout()plt.show()``````{python}#| label: fig-earnings-change-dist#| fig-cap: "Phân phối thay đổi lợi nhuận theo năm quanh mức không. Một sự gián đoạn ở đây gợi ý rằng các doanh nghiệp quản trị lợi nhuận để tránh báo cáo sụt giảm, dù nhỏ."# Year-over-year changesearn_changes = np.diff(earn_array.reshape(n_firms_dist, n_years_dist), axis=1).flatten()fig, ax = plt.subplots(figsize=(8, 5))bins_chg = np.arange(-0.15, 0.15, 0.005)ax.hist(earn_changes, bins=bins_chg, color="darkorange", edgecolor="white", alpha=0.85, density=True)ax.axvline(0, color="firebrick", linestyle="--", linewidth=1.5, label="Zero change")ax.set_xlabel("Change in Earnings / Total Assets")ax.set_ylabel("Density")ax.set_title("Earnings Change Distribution Around Zero")ax.legend()plt.tight_layout()plt.show()```### Quản trị lợi nhuận dựa trên dồn tích so với quản trị lợi nhuận thực@cohen2008real ghi nhận sự chuyển dịch từ AEM sang REM sau khi Đạo luật Sarbanes-Oxley (SOX) được thông qua năm 2002, cho thấy việc giám sát quy định chặt chẽ hơn đẩy hoạt động thao túng sang các kênh khó phát hiện hơn. @zang2012evidence cung cấp thêm bằng chứng rằng các doanh nghiệp đánh đổi giữa AEM và REM dựa trên chi phí tương đối của chúng.Ở Việt Nam, nơi việc thực thi chuẩn mực kế toán yếu hơn so với nước Mỹ thời hậu SOX, ta có thể kỳ vọng AEM vẫn là kênh chiếm ưu thế. Tuy nhiên, khi Việt Nam tiến tới áp dụng IFRS và tăng cường giám sát của SSC, giả thuyết thay thế từ AEM sang REM trở nên có thể kiểm định được.Chúng ta có thể đo REM bằng cách tiếp cận của @roychowdhury2006earnings. Ba chỉ báo thay thế nắm bắt các kênh thao túng khác nhau:**Dòng tiền hoạt động bất thường.** Ước lượng CFO bình thường như một hàm của doanh thu và thay đổi doanh thu:$$\frac{CFO_{i,t}}{A_{i,t-1}} = \beta_0 + \beta_1 \frac{1}{A_{i,t-1}} + \beta_2 \frac{S_{i,t}}{A_{i,t-1}} + \beta_3 \frac{\Delta S_{i,t}}{A_{i,t-1}} + \varepsilon_{i,t}$$ {#eq-abnormal-cfo}**Chi phí sản xuất bất thường.** Chi phí sản xuất = giá vốn hàng bán (COGS) + thay đổi hàng tồn kho. Mức bình thường được mô hình hóa như sau:$$\frac{PROD_{i,t}}{A_{i,t-1}} = \beta_0 + \beta_1 \frac{1}{A_{i,t-1}} + \beta_2 \frac{S_{i,t}}{A_{i,t-1}} + \beta_3 \frac{\Delta S_{i,t}}{A_{i,t-1}} + \beta_4 \frac{\Delta S_{i,t-1}}{A_{i,t-1}} + \varepsilon_{i,t}$$ {#eq-abnormal-prod}**Chi tiêu tùy ý bất thường.** R&D + quảng cáo + chi phí bán hàng và quản lý (SGA), được mô hình hóa như sau:$$\frac{DISC_{i,t}}{A_{i,t-1}} = \beta_0 + \beta_1 \frac{1}{A_{i,t-1}} + \beta_2 \frac{S_{i,t-1}}{A_{i,t-1}} + \varepsilon_{i,t}$$ {#eq-abnormal-disc}Phần dư từ các hồi quy này đóng vai trò chỉ báo thay thế cho thao túng thực. Một doanh nghiệp sản xuất vượt mức sẽ có chi phí sản xuất *cao* bất thường và CFO *thấp* bất thường (tiền bị giam trong hàng tồn kho).## Tóm tắtChương này đã xem xét việc đo lường và phát hiện quản trị lợi nhuận, tập trung vào tính chặt chẽ về phương pháp luận và sự điều chỉnh cho môi trường thể chế của Việt Nam. Các điểm chính cần ghi nhớ là:- Phát hiện quản trị lợi nhuận đòi hỏi tách dồn tích tùy ý khỏi dồn tích không tùy ý, điều này phụ thuộc quyết định vào chất lượng của mô hình dồn tích không tùy ý. Cả năm mô hình kinh điển đều có những điểm yếu đã biết.- Dưới giả thuyết không là không có thao túng, các mô hình Jones và Jones điều chỉnh bác bỏ quá mức khi dùng sai số chuẩn hai giai đoạn tiêu chuẩn. Hiệu chỉnh của @salkever1976use cho phép suy luận được hiệu chỉnh đúng.- Khi các doanh nghiệp kiểm định có kết quả tài chính cực đoan, mọi mô hình đều có mức ý nghĩa thực tế lệch nghiêm trọng khỏi mức danh nghĩa, quy nhầm biến thiên dồn tích do kết quả hoạt động cho sự tùy ý của nhà quản lý. Ghép cặp theo hiệu quả hoạt động [@kothari2005performance] giải quyết một phần vấn đề này.- Phân tích sức mạnh kiểm định cho thấy các mức thao túng hợp lý về mặt kinh tế (dưới 10% tài sản) được phát hiện với xác suất rất thấp. Điều này đặt nghi vấn về các nghiên cứu báo cáo kết quả không bác bỏ như bằng chứng của việc không có thao túng.- Các đặc điểm thể chế của Việt Nam, như quản trị DNNN, quy tắc kế toán VAS, thực thi yếu và phạm vi kiểm toán mỏng, tạo ra bối cảnh phong phú cho nghiên cứu quản trị lợi nhuận, nhưng các thách thức phương pháp luận bị khuếch đại bởi chuỗi thời gian ngắn hơn và dữ liệu nhiễu hơn.Các nhà nghiên cứu làm việc với dữ liệu Việt Nam nên: (i) dùng hiệu chỉnh Salkever để suy luận đúng, (ii) triển khai ghép cặp theo hiệu quả hoạt động, (iii) xem xét nhiều mô hình và đối chiếu chéo kết quả, và (iv) bổ sung cho các phương pháp dựa trên dồn tích bằng quản trị lợi nhuận thực và các kiểm định về phân phối.<!-- ## Bài tập1. **Tương đương Salkever.** Dùng hàm `demonstrate_salkever()`, hãy kiểm chứng bằng số rằng ước lượng $DA$ Jones hai giai đoạn bằng hệ số Salkever trên $PART$ cho một doanh nghiệp được chọn ngẫu nhiên. Báo cáo cả hai ước lượng đến sáu chữ số thập phân.2. **Jones điều chỉnh với Salkever.** Mở rộng cách tiếp cận Salkever cho mô hình Jones điều chỉnh. Trong hồi quy một giai đoạn, $\Delta Rev$ nên được xác định là đã điều chỉnh hay chưa điều chỉnh? Hãy biện luận cho lựa chọn của bạn.3. **Ghép cặp theo hiệu quả hoạt động.** Triển khai quy trình ghép cặp theo hiệu quả hoạt động của @kothari2005performance: với mỗi quan sát doanh nghiệp–năm kiểm định, tìm một doanh nghiệp đối chứng cùng ngành 2 chữ số có ROA gần nhất, rồi trừ $DA$ của nó. Chạy lại phân tích sai lầm loại I với $DA$ đã ghép cặp. Việc ghép cặp có làm giảm tình trạng bác bỏ quá mức đối với các mẫu có hiệu quả hoạt động cực đoan không?4. **Phát hiện ở DNNN so với doanh nghiệp ngoài nhà nước.** Chia mẫu theo tình trạng DNNN và ước lượng dồn tích tùy ý riêng cho từng mẫu con. Có sự khác biệt hệ thống nào trong $DA$ ước lượng có thể phản ánh khác biệt thực sự về chất lượng dồn tích, hay chúng có thể là sản phẩm nhân tạo của cách đặc tả mô hình?5. **Kiểm định gián đoạn lợi nhuận.** Dùng dữ liệu lợi nhuận tổng hợp (hoặc dữ liệu thực của Việt Nam nếu có), hãy kiểm định chính thức sự gián đoạn tại mức không theo cách tiếp cận của @burgstahler1997earnings. Tính chênh lệch chuẩn hóa giữa khoảng ngay trên và ngay dưới mức không: $$ z = \frac{n_{+} - n_{-}}{\sqrt{N \cdot p \cdot (1-p)}} $$ trong đó $n_{+}$ và $n_{-}$ là số quan sát trong hai khoảng liền kề và $p$ là tỷ lệ kỳ vọng dưới giả định phân phối trơn.6. **Quản trị lợi nhuận thực.** Triển khai mô hình @roychowdhury2006earnings cho chi phí sản xuất bất thường (@eq-abnormal-prod) bằng panel tổng hợp. Ước lượng mô hình theo mặt cắt ngang theo từng năm và ngành 2 chữ số. Mô hình giải thích được bao nhiêu phần biến thiên mặt cắt ngang của chi phí sản xuất?7. **Sức mạnh kiểm định trong điều kiện Việt Nam.** Chạy lại phân tích sức mạnh kiểm định với cửa sổ ước lượng rút ngắn (7 năm thay vì 10) để mô phỏng mức sẵn có dữ liệu điển hình của các doanh nghiệp Việt Nam niêm yết sau năm 2007. Việc giảm dữ liệu ước lượng ảnh hưởng thế nào đến sức mạnh phát hiện? Mức thao túng tối thiểu có thể phát hiện với sức mạnh 50% là bao nhiêu?8. **Thao túng doanh thu trong kỳ lẻ (stub period).** @stubben2010discretionary đề xuất một thước đo quản trị lợi nhuận dựa trên doanh thu, hồi quy thay đổi khoản phải thu theo thay đổi doanh thu, cho rằng thao túng doanh thu dễ phát hiện qua dấu vết khoản phải thu hơn là qua các mô hình dồn tích rộng. Hãy triển khai cách tiếp cận này và so sánh tính chất sai lầm loại I và sức mạnh kiểm định của nó với mô hình Jones trên dữ liệu Việt Nam. -->