# Stata：投资组合有效边界

Stata连享会   主页 || 视频 || 推文 || 知乎

New！ `lianxh` 命令发布了：

`. ssc install lianxh`

`. help lianxh`

⛳ Stata 系列推文：

E-Mail: shijy2000@outlook.com

E-mail: arlionn@163.com

## 2. 股票数据获取与预处理

### 2.1 获取股票数据

``````ssc install cntrade, replace
ssc install openall, replace
``````

``````  local list "600519 603259 002230"
openall `list'
gen year = year(date)
keep if year == 2020 //保留2020年数据
save "mstocks_long.dta", replace //保存合并后的数据

use "mstocks_long.dta", clear  // Long format
keep stkcd date clsprc //保留需要纵横变换的变量
xtset date stkcd
reshape wide clsprc, i(date) j(stkcd)
save "mstocks_wide.dta", replace  // Wide format

``````

### 2.2 观察股票价格走势

`````` use mstocks_wide, clear
foreach i of varlist clsprc*{
if "`i'" != "date"{
replace `i' = (`i' / `=`i'[1]') * 100
format `i' %6.2f
}
}  //标准化股价

tw
line  clsprc*   date, ///
xla(21915(45)22281, ang(20)) ///
leg(order(1 "贵州茅台" 2 "药明康德" ///
3 "科大讯飞" ) position(1) ring(0)) ///
title("股价走势图（2020年）") ///
xtitle("日期") ///
ytitle("标准化股价")
graph export "\$out\price_trend.png", replace
``````

### 2.3 计算收益率与协方差

${r}_{t}=\mathrm{log}\left(\frac{{P}_{t}}{{P}_{t-1}}\right)=\mathrm{log}\left({P}_{t}\right)-\mathrm{log}\left({P}_{t-1}\right)$

``````use mstocks_wide, clear
gen dateid = _n
tsset dateid
foreach i of varlist clsprc*{
gen l`i' = l.`i'
replace `i' = log(`i'/l`i')
drop l`i'
}
drop dateid
rename (clsprc2230 clsprc600519 clsprc603259)///
(科大讯飞 贵州茅台 药明康德)
save return, replace

``````

``````list in 1/5

|       date     科大讯飞     贵州茅台     药明康德 |
|---------------------------------------------------|
1. | 2020-01-02            .            .            . |
2. | 2020-01-03   -.01090398   -.04659081   -.02609613 |
3. | 2020-01-06    .05773528   -.00052862   -.03025364 |
4. | 2020-01-07    .00081666    .01522685    .01501375 |
5. | 2020-01-08   -.01923136   -.00585523   -.00627605 |
``````

``````use return, clear
drop in 1
local j = 1
foreach i of varlist 科大讯飞 贵州茅台 药明康德{
qui sum `i'
local r`j' = r(mean)
local j = `j' + 1
}
mat rets = (`r1', `r2', `r3')// 年均收益率矩阵

corr 科大讯飞 贵州茅台 药明康德, cov
mat cov = r(C) // 协方差矩阵
``````

``````mat list rets

rets[1,3]
c1         c2         c3
r1  .00063598  .00235508  .00159318

mat list cov

symmetric cov[3,3]
科大讯飞      贵州茅台      药明康德
科大讯飞     .00068277
贵州茅台     .00018373     .00032969
药明康德     .00032823     .00023092     .00115149
``````

## 3. 构造投资组合

### 3.1 两项资产的情况

``````clear
set obs 11
egen double w1=fill(0(0.1)1)
format w1 %tg
gen w2=1-w1
format w2 %tg

gen r_P = w1*rets[1,1] + w2*rets[1,2]
gen varP= w1^2*cov[1,1] + w2^2*cov[2,2] ///
+ 2*w1*w2*cov[2,1]
gen sdP=sqrt(varP)

twoway (scatter r_P sdP, msize(medlarge)  ///
mlabel(w1) mlabcolor(edkblue)),   ///
ytitle(收益率)   ///
ylabel(#5)      ///
xtitle(波动性)  ///
title(Frontier using ///
2 stocks(科大讯飞 & 贵州茅台))

graph export "\$out\Frontier_using_2_stocks.png" ///
, as(png) replace
``````

### 3.2 添加第三项资产

``````clear
set obs 101
egen double w1=fill(0(0.01)1)
format w1 %tg
egen double w2=fill(0(0.01)1)
gen w3=1-w1-w2
format w2 %tg
format w3 %tg

gen r_P = w1*rets[1,1] + w2*rets[1,2] + w3*rets[1,3]

gen varP= w1^2*cov[1,1] + w2^2*cov[2,2] ///
+ w3^2*cov[3,3]    ///
+ 2*w1*w3*cov[1,3] ///
+ 2*w2*w3*cov[2,3] ///
+ 2*w1*w2*cov[2,1]

gen sdP=sqrt(varP)

twoway (scatter r_P sdP, msize(tiny) ///
mlabcolor(edkblue)), ///
ytitle(收益率) ylabel(#5) xtitle(波动性) ///
title("Frontier with 3 stocks")         ///
subtitle("(科大讯飞 & 贵州茅台 & 药明康德)")

graph export "\$out\Frontier_using_3_stocks.png"///
, as(png) replace
``````

## 4. 计算并绘制有效边界

### 4.1 蒙特卡洛模拟初窥边界

``````cap prog drop front
prog def front, rclass
version 15.0
use return, clear
local w1 = runiform()
local w2 = runiform()
local w3 = runiform()
mat weight = (`w1' \ `w2' \ `w3' )
mat list weight
mat weight = weight / (`w1'+`w2'+`w3')
mat list weight
ret scalar w1 = weight[1, 1]
ret scalar w2 = weight[2, 1]
ret scalar w3 = weight[3, 1]
local j = 1
foreach i of varlist _all{
if "`i'" != "date"{
qui sum `i'
local r`j' = r(mean)
local j = `j' + 1
}
}
mat rets = (`r1', `r2', `r3')
mat a =  rets * weight
mat list a
ret scalar ret = a[1, 1]
corr 科大讯飞 贵州茅台 药明康德, cov
ret list
mat cov = r(C)
mat b =  weight' * cov * weight
mat list b
ret scalar var = b[1, 1]
ret scalar std = sqrt(b[1, 1])
end
``````

``````simulate ret = r(ret)   ///
var = r(var)   ///
std = r(std)   ///
w1 = r(w1)     ///
w2 = r(w2)     ///
w3 = r(w3)     ///
, reps(100000): front
save dataset, replace
graph export "\$out\Portfolio.png", as(png) replace
``````

### 4.2 最优化与有效边界计算

``````mata:
mata clear
void min_std(real scalar todo,///
real vector w12, std, g, H)
{
real scalar w3
w3 = 1 - sum(w12)
real vector r_mean
r_mean= st_matrix("rets")
// 将储存于 Stata 的矩阵导入 Mata环境
real vector w
w = (w12, w3)
real scalar r_P
r_P = w * r_mean'
real matrix var_P
var_P = st_matrix("cov")
var_P = w * var_P * w'
std = -sqrt(var_P[1, 1])
// 加入负号以达到求最小值的目的
}

S = optimize_init()
optimize_init_evaluator(S, &min_std())
optimize_init_params(S, J(1, 2, 0))
wh = optimize(S)

w = (wh, 1-sum(wh))
r_Pm = (wh, 1-sum(wh)) * st_matrix("rets")'
var_P = (w * st_matrix("cov") * w')
std = sqrt(var_P[1, 1])

w
r_Pm
std

end
``````

``````     1             2             3
+-------------------------------------------+
1 |  .2085128365    .744359616   .0471275475  |
+-------------------------------------------+

``````

``````mata:
mata clear
void min_std(real scalar todo,///
real vector w123, std, g, H)
{
real vector rmean
rmean = st_matrix("rets")
real scalar rp
real vector w
w = w123
rp = w * rmean'
real matrix variancep
variancep = st_matrix("cov")
variancep = w * variancep * w'
std = -sqrt(variancep[1, 1])
}

std_vector = J(1, 40, 0)

// 最小化方差对应的收益率为 0.00196，
// 此时收益率较低，为仅购入贵州茅台时的 0.00235

j=1
for (i = 0.00196; i < 0.00235; i = i + 0.00001)
{
S = optimize_init()
optimize_init_evaluator(S, &min_std())
optimize_init_technique(S, "nr")
optimize_init_constraints(S, ///
((st_matrix("rets")\ J(1, 3, 1)), (i \ 1)))
optimize_init_params(S, J(1, 3, 0))
wh = optimize(S)
variancep = (wh * st_matrix("cov") * wh')
std = sqrt(variancep[1, 1])
std_vector[1, j] = std
j = j + 1
}
st_matrix("std_vector", std_vector)

end
``````

``````clear
set obs 40
gen ret = (_n + 195) / 100000
gen std = .
forval i = 1/40{
replace std = std_vector[1, `i'] in `i'
}
gen front = 1
drop if std == 0
save front, replace

tw ///
sc ret std if front == 1, ///
msize(tiny) msymbol(D) ///
mc("blue") leg(off) || ///
scatteri .0019607171  ///
.0171638423 "最小方差点", ///
mc("red")  msymbol(o) mlabc("pink")
``````

``````use dataset1, clear
append using front

twoway ///
scatter ret std, msize(*0.01) ///
xtitle(波动率) ytitle(收益率) ///
title("Efficient Frontier using 3 stocks")///
msymbol(o) ///
xlabel(#6, format(%6.3f)) ylabel(, ///
format(%6.4f))||    scatteri  ///
.0019607171   .01716384 "最小方差点", ///
mc("pink")  msymbol(o) mlabc("pink") || ///
scatter ret std if front == 1, ///
msize(tiny) msymbol(D) ///
mc("blue") leg(off)

graph export ///
"\$out\Investment_portfolio_using_3_stocks.png"///
, as(png) replace
``````

## 5. 快捷命令

``````use return.dta, clear
gmvport 科大讯飞 贵州茅台 药明康德, noshort

Number of observations used to calculate///
expected returns and var-cov matrix : 243
The weight vector of the Global Minimum ///
Variance Portfolio (NOT Allow Short Sales) is:

Weights
科大讯飞  .20851284
贵州茅台  .74435962
药明康德  .04712755

The return of the Global Minimum Variance ///
Portfolio is: .00196288

The standard deviation (risk) of the Global ///
Minimum Variance Portfolio is: .01716384

``````

``````use return.dta, clear
efrontier 科大讯飞 贵州茅台 药明康德
``````

``````findit mvport
``````

## 7. 参考资料

### Stata 有效前沿的相关命令

• `findit mvport` // 一组计算投资效率和投资组合的命令
• `help grsftest` // Econometrica 57(5)
• Gibbons, M.R., S. Ross, and J. Shanken, 1989. "A test of the efficiency of a given portfolio" Econometrica, 57(5), 1121-1152. - PDF -
• `search fetchcomponents` // Stata Journal 13-3
• Mehmet F. Dicle, 2013, Financial Portfolio Selection using the Multifactor Capital Asset Pricing Model and Imported Options Data, Stata Journal, 13(3): 603–617. - PDF -

## 8. 相关推文

Note：产生如下推文列表的 Stata 命令为：
`lianxh 投资组合 收益 事件研究`

`ssc install lianxh, replace`

## 相关课程

### 最新课程-直播课

• Note: 部分课程的资料，PPT 等可以前往 连享会-直播课 主页查看，下载。

### 关于我们

• Stata连享会 由中山大学连玉君老师团队创办，定期分享实证分析经验。
• 连享会-主页知乎专栏，400+ 推文，实证分析不再抓狂。直播间 有很多视频课程，可以随时观看。
• 公众号关键词搜索/回复 功能已经上线。大家可以在公众号左下角点击键盘图标，输入简要关键词，以便快速呈现历史推文，获取工具软件和数据下载。常见关键词：`课程, 直播, 视频, 客服, 模型设定, 研究设计, stata, plus, 绘图, 编程, 面板, 论文重现, 可视化, RDD, DID, PSM, 合成控制法`

✏ 连享会-常见问题解答：
https://gitee.com/lianxh/Course/wikis

New！ `lianxh` 命令发布了：

`. ssc install lianxh`

`. help lianxh`