version 15.0 clear all set more off set type double set linesize 160 capture log close _all * Edit only this working-directory line if the folder is moved. cd "C:/Users/cattom/Documents/econometrics/Week8" log using "week8_stata.log", text replace display "Week 8: residual degrees of freedom and RESSET-CSMAR merge" display "All financial values are preserved in their original source scale." tempname audit dict postfile `audit' str60 metric double value using "processing_audit.dta", replace postfile `dict' str32 variable str140 description str32 source_unit str18 source using "variable_dictionary.dta", replace * 1. RESSET: read data below its Chinese header, retaining numeric precision. import excel using "data/FININDRATIO_OLD_5938AD12016_(锐思).xls", sheet("FININDRATIO_OLD") cellrange(A2) clear rename (A B C D E F G H I J) (Comcd Lcomnm A_Stkcd B_Stkcd H_Stkcd Lstflg Enddt Reporttype ROA ROE) post `audit' ("resset_input_rows") (_N) generate long resset_excel_row = _n + 1 generate str6 stkcd = strtrim(A_Stkcd) assert regexm(stkcd,"^[0-9]+$") & strlen(stkcd) <= 6 generate byte code_format_exception = strlen(stkcd) != 6 assert stkcd == "0991" & inlist(year(Enddt),1998,1999) if code_format_exception quietly count if code_format_exception post `audit' ("resset_code_format_exceptions") (r(N)) assert Lstflg == "A" assert missing(B_Stkcd) & missing(H_Stkcd) assert Reporttype == "Q4" assert month(Enddt) == 12 & day(Enddt) == 31 generate int year = year(Enddt) assert !missing(stkcd,year) isid stkcd year post `audit' ("resset_duplicate_key_excess") (0) quietly summarize year post `audit' ("resset_min_year") (r(min)) post `audit' ("resset_max_year") (r(max)) egen byte firm_tag = tag(stkcd) quietly count if firm_tag post `audit' ("resset_distinct_codes") (r(N)) drop firm_tag foreach v in ROA ROE { quietly count if missing(`v') post `audit' ("resset_missing_`v'") (r(N)) } format Enddt %tdCCYY-NN-DD format ROA ROE %24.17g label variable stkcd "Source security code as text; normally six digits" label variable code_format_exception "Source code has nonstandard length; preserved without guessing" label variable year "Report year, not announcement year" label variable ROA "资产净利率;原表标注(%);原值未换算" label variable ROE "净资产收益率(摊薄);原表标注(%);原值未换算" label variable Enddt "RESSET报告截止日期" label variable resset_excel_row "Row number in original RESSET worksheet" label variable Lcomnm "源文件中的最新公司全称,非逐年历史名称" post `dict' ("stkcd") ("证券代码文本;通常六位;原始0991的两条记录保留原样") ("文本标识") ("derived") post `dict' ("code_format_exception") ("源代码非六位标记;0991两条记录未推测补零") ("0/1") ("derived") post `dict' ("year") ("报告截止日期的年份,不是公告年份") ("年") ("derived") post `dict' ("ROA") ("资产净利率;保留原值,不乘除100,经济尺度需原库数据字典确认") ("源表标注%;原值") ("RESSET") post `dict' ("ROE") ("净资产收益率(摊薄);保留原值,不乘除100,经济尺度待核") ("源表标注%;原值") ("RESSET") post `dict' ("Comcd") ("上市公司代码") ("文本标识") ("RESSET") post `dict' ("Lcomnm") ("最新公司全称,不能直接视为当年公司名称") ("文本") ("RESSET") post `dict' ("A_Stkcd") ("A股股票代码;原始列") ("文本标识") ("RESSET") post `dict' ("B_Stkcd") ("B股股票代码;本文件全空") ("文本标识") ("RESSET") post `dict' ("H_Stkcd") ("H股股票代码;本文件全空") ("文本标识") ("RESSET") post `dict' ("Lstflg") ("源文件上市标识;全为A,不额外推断历史上市状态") ("原始编码") ("RESSET") post `dict' ("Enddt") ("RESSET报告截止日期") ("日期") ("RESSET") post `dict' ("Reporttype") ("报表类型;本文件全为Q4且日期均为12月31日") ("原始编码") ("RESSET") post `dict' ("resset_excel_row") ("RESSET原始工作表行号") ("行") ("provenance") compress sort stkcd year save "resset_financial_all_years.dta", replace * 2. CSMAR: retain every original governance field; append the two periods. tempfile gov_first foreach period in "1999-2012" "2013-2014" { import excel using "data/CG_Ybasic`period'.xls", sheet("CG_Ybasic") firstrow allstring clear assert Stkcd[1] == "证券代码" assert Stkcd[2] == "没有单位" foreach v of varlist _all { local description = `v'[1] local unit = `v'[2] label variable `v' "`description'" if "`period'" == "1999-2012" & "`v'" != "Stkcd" { post `dict' ("`v'") ("`description'") ("`unit'") ("CSMAR") } } drop in 1/2 generate long csmar_excel_row = _n + 3 post `audit' ("csmar_`period'_input_rows") (_N) rename Stkcd stkcd replace stkcd = strtrim(stkcd) assert regexm(stkcd,"^[0-9][0-9][0-9][0-9][0-9][0-9]$") generate double csmar_date = daily(Reptdt,"YMD") generate double csmar_announcement = daily(Annodt,"YMD") assert !missing(csmar_date) assert !missing(csmar_announcement) if strtrim(Annodt) != "" assert month(csmar_date) == 12 & day(csmar_date) == 31 generate int year = year(csmar_date) assert inrange(year,1999,2012) if "`period'" == "1999-2012" assert inrange(year,2013,2014) if "`period'" == "2013-2014" destring Y0301b Y0401b Y0501b Y0601b Y0701b Y1001b Y1101a Y1101b Y1201a Y1301b Bddihldn Bsuphldn Excuhldn Mngmhldn Y1401b Y1501a Y1501b Y1501c Y1501d Y1501e Y1601a Y1601b Y1601c Y1701a Y1701b Y1701c Y1801b, replace generate str28 csmar_source = "CG_Ybasic`period'.xls" format csmar_date csmar_announcement %tdCCYY-NN-DD isid stkcd year if "`period'" == "1999-2012" save `gov_first', replace } append using `gov_first' isid stkcd year post `audit' ("csmar_total_rows") (_N) post `audit' ("csmar_duplicate_key_excess") (0) egen byte firm_tag = tag(stkcd) quietly count if firm_tag post `audit' ("csmar_distinct_codes") (r(N)) drop firm_tag label variable csmar_date "CSMAR统计截止日期;由Reptdt解析" label variable csmar_announcement "CSMAR公告日期;由Annodt解析" label variable csmar_source "Original CSMAR filename" label variable csmar_excel_row "Row number in original CSMAR worksheet" post `dict' ("csmar_date") ("由Reptdt解析的统计截止日期") ("日期") ("derived") post `dict' ("csmar_announcement") ("由Annodt解析的公告日期;不用于当期年份匹配") ("日期") ("derived") post `dict' ("csmar_source") ("原CSMAR文件名") ("文本") ("provenance") post `dict' ("csmar_excel_row") ("CSMAR原始工作表行号") ("行") ("provenance") sort stkcd year compress save "csmar_governance_1999_2014.dta", replace * 3. Full outer 1:1 merge: retain all years and explicitly mark unmatched rows. use "resset_financial_all_years.dta", clear merge 1:1 stkcd year using "csmar_governance_1999_2014.dta" assert _merge == 1 if code_format_exception == 1 replace code_format_exception = 0 if _merge == 2 assert Enddt == csmar_date if _merge == 3 isid stkcd year generate byte in_resset = inlist(_merge,1,3) generate byte in_csmar = inlist(_merge,2,3) generate byte matched = _merge == 3 generate byte complete_roa_roe = matched & !missing(ROA,ROE) label define merge_source 1 "RESSET only" 2 "CSMAR only" 3 "Matched", replace label values _merge merge_source label variable complete_roa_roe "Matched record with both ROA and ROE observed" foreach v in in_resset in_csmar matched complete_roa_roe { label variable `v' "`v': 1=yes, 0=no" } post `dict' ("_merge") ("合并状态:1仅RESSET,2仅CSMAR,3两库匹配") ("编码1/2/3") ("derived") post `dict' ("in_resset") ("是否在RESSET文件出现;1是0否") ("0/1") ("derived") post `dict' ("in_csmar") ("是否在CSMAR文件出现;1是0否") ("0/1") ("derived") post `dict' ("matched") ("是否两库匹配;1是0否") ("0/1") ("derived") post `dict' ("complete_roa_roe") ("两库匹配且ROA/ROE均非缺失;1是0否") ("0/1") ("derived") post `audit' ("merged_total_rows") (_N) forvalues s = 1/3 { quietly count if _merge == `s' post `audit' ("merge_status_`s'") (r(N)) } quietly count if complete_roa_roe post `audit' ("matched_complete_roa_roe") (r(N)) egen byte firm_tag = tag(stkcd) if matched quietly count if firm_tag == 1 post `audit' ("matched_distinct_codes") (r(N)) drop firm_tag quietly count if _merge == 1 & year < 1999 post `audit' ("resset_only_before_1999") (r(N)) quietly count if _merge == 1 & year >= 1999 post `audit' ("resset_only_from_1999") (r(N)) foreach v in ROA ROE { quietly count if matched & missing(`v') post `audit' ("matched_missing_`v'") (r(N)) } order stkcd year ROA ROE _merge in_resset in_csmar matched complete_roa_roe sort stkcd year format ROA ROE %24.17g char _dta[scope] "All observations supplied by user; not a certified census of listed firms." char _dta[units] "ROA/ROE raw source values retained; headers say percent; economic scale not independently verified." char _dta[merge] "1:1 stkcd year; financial master, governance using; full outer merge." save "financial_governance_all_years.dta", replace preserve * Stata display formats can round large holdings/pay values in CSV. * Export all non-date numeric columns with full double precision. quietly ds, has(type numeric) local numeric_vars `r(varlist)' local date_vars Enddt csmar_date csmar_announcement local precise_vars : list numeric_vars - date_vars format `precise_vars' %24.17g export delimited using "financial_governance_all_years.csv", datafmt nolabel quote replace restore preserve keep if matched save "financial_governance_matched.dta", replace restore preserve keep if !matched keep stkcd year _merge ROA ROE Comcd Lcomnm Enddt Reptdt csmar_source resset_excel_row csmar_excel_row export delimited using "unmatched_records.csv", datafmt nolabel quote replace restore * 4. Year-by-year coverage and missingness; structural absence is separate. preserve generate byte resset_only = _merge == 1 generate byte csmar_only = _merge == 2 generate byte missing_roa = in_resset & missing(ROA) generate byte missing_roe = in_resset & missing(ROE) collapse (sum) resset_n=in_resset csmar_n=in_csmar matched_n=matched complete_n=complete_roa_roe resset_only csmar_only missing_roa missing_roe, by(year) generate double pct_resset_matched = 100*matched_n/resset_n generate double pct_csmar_matched = 100*matched_n/csmar_n format pct* %12.6f save "merge_by_year.dta", replace export delimited using "merge_by_year.csv", datafmt replace list, noobs separator(0) set scheme s2color twoway (line resset_n year, lcolor(navy) lwidth(medthick)) (line csmar_n year, lcolor(teal) lwidth(medthick)) (line matched_n year, lcolor(orange) lwidth(medthick)), title("Annual coverage in the supplied files") subtitle("Observations by report year; not a market census") xtitle("Report year") ytitle("Company-year records") xlabel(1990(2)2014, angle(45)) legend(order(1 "RESSET" 2 "CSMAR" 3 "Matched") rows(1)) graphregion(color(white)) name(coverage, replace) graph save "annual_coverage.gph", replace graph export "annual_coverage.png", width(1800) replace restore * 5. Descriptive statistics on the unchanged source scale. tempname desc postfile `desc' str20 sample str8 variable long observations long missing_count double mean double sd double min double p1 double p25 double p50 double p75 double p99 double max using "descriptive_statistics.dta", replace foreach sample in resset_all matched matched_complete { local condition "in_resset == 1" if "`sample'" == "matched" local condition "matched == 1" if "`sample'" == "matched_complete" local condition "complete_roa_roe == 1" foreach v in ROA ROE { quietly count if (`condition') & missing(`v') local nm = r(N) quietly summarize `v' if `condition', detail post `desc' ("`sample'") ("`v'") (r(N)) (`nm') (r(mean)) (r(sd)) (r(min)) (r(p1)) (r(p25)) (r(p50)) (r(p75)) (r(p99)) (r(max)) } } postclose `desc' preserve use "descriptive_statistics.dta", clear format mean-max %24.17g export delimited using "descriptive_statistics.csv", datafmt replace list sample variable observations missing_count mean p50 min max, noobs restore * Preserve a short list of source extremes for transparent follow-up. preserve keep if in_resset keep stkcd year Comcd Lcomnm ROA ROE resset_excel_row generate byte extreme = 0 foreach v in ROA ROE { quietly summarize `v', detail replace extreme = 1 if inlist(`v',r(min),r(max)) & !missing(`v') } keep if extreme drop extreme export delimited using "source_extremes.csv", datafmt quote replace restore * 6. Ordinary OLS example to verify residual df; no causal interpretation. * Using 2013 (a single cross-section) avoids implying panel-error independence. generate double board_size = Y1101a generate double independent_share = Y1101b/Y1101a if Y1101a > 0 & !missing(Y1101a,Y1101b) generate byte valid_board = board_size > 0 & !missing(board_size,independent_share) & inrange(independent_share,0,1) quietly count if matched & year == 2013 & !valid_board post `audit' ("ols_2013_excluded_board_records") (r(N)) regress ROA board_size independent_share if matched & year == 2013 & valid_board estimates save "df_example_ols.ster", replace scalar n_ols = e(N) scalar k_ols = e(df_m) scalar rank_ols = e(rank) scalar df_ols = e(df_r) scalar sse_ols = e(rss) scalar s2_ols = e(rss)/e(df_r) scalar rmse2_ols = e(rmse)^2 scalar naive_s2 = e(rss)/e(N) assert scalar(k_ols) == 2 assert scalar(rank_ols) == 3 assert scalar(df_ols) == scalar(n_ols)-3 assert reldif(scalar(s2_ols),scalar(rmse2_ols)) < 1e-12 predict double residual if e(sample), residuals generate double residual_sq = residual^2 quietly summarize residual_sq, meanonly scalar residual_sse = r(sum) assert reldif(scalar(residual_sse),scalar(sse_ols)) < 1e-10 quietly summarize residual, meanonly scalar residual_sum = r(sum) generate double board_residual = board_size*residual quietly summarize board_residual, meanonly scalar board_residual_sum = r(sum) generate double independent_residual = independent_share*residual quietly summarize independent_residual, meanonly scalar independent_residual_sum = r(sum) assert abs(scalar(residual_sum)) < 1e-7 assert abs(scalar(board_residual_sum)) < 1e-6 assert abs(scalar(independent_residual_sum)) < 1e-7 tempname dfout postfile `dfout' str36 metric double value using "df_example_metrics.dta", replace foreach s in n_ols k_ols rank_ols df_ols sse_ols s2_ols rmse2_ols naive_s2 residual_sse residual_sum board_residual_sum independent_residual_sum { post `dfout' ("`s'") (scalar(`s')) } postclose `dfout' preserve keep if e(sample) keep stkcd year ROA board_size independent_share residual residual_sq save "df_example_sample.dta", replace restore postclose `audit' postclose `dict' foreach f in processing_audit variable_dictionary df_example_metrics { use "`f'.dta", clear capture format value %24.17g export delimited using "`f'.csv", datafmt quote replace } use "financial_governance_all_years.dta", clear isid stkcd year tabulate _merge display "WEEK8_ANALYSIS_COMPLETED_SUCCESSFULLY" log close exit, clear