用Python对CAPM和Fama French Three Factor model的初步学习

  • 概述
  • 介绍
  • 建模与分析
    • CAPM
    • Fama French Three-Factor Model
  • 总结

概述

本文主要使用CAPM(资本资产定价模型)和Fama French Three Factor model来评估中国股票市场的股票价格。 使用CAPM来选择投资组合,然后建立Fama French Three Factor model来评估投资组合。
首先,使用SML绘制CAPM图表,然后随机选择50只股票将其在图上标记,保存高于该线的股票。 接下来显示这些股票之间的相关性。 之后根据收益率和相关性选择我们的投资组合并分配quantity。
其次,建立Fama French Three Factor model,包括计算三个因素,并使用投资组合的回报率进行回归。 在这一部分中,编写了两个函数来使代码更加清晰和高效。
总的来说,本文有三个部分,介绍,建模和分析,以及代码。

介绍

关于两个模型介绍部分不多赘述。简单看一下公式。

建模与分析

CAPM

本文用的股票数据来源于Tushare,可以注册获取API。官方学生认证的话可以加2000积分。
首先,引入一些第三方库

import tushare
import requests
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import random
import time
pro = tushare.pro_api('官网注册获取')

无风险利率用的是中国国债利率,找了个均值,如果能有时间序列的无风险利率更好,大家如果知道怎么获取到的话,可以留言。
这里用国证指数来表示市场回报率。

# drew the CAPM picture, we need rf and rm
gzA = pro.index_daily(ts_code='399317.SZ', start_date='20000101', end_date='20190901')
gzA = gzA.sort_values('trade_date', ascending=True)
rf = 0.03064  # 3.064%
rm = gzA['pct_chg'].mean()

这里获取市场上股票列表,有3672支股。

stock_basic = pro.stock_basic()
stock_basic.head()

output:

随机选取50支股票,计算Beta和收益率,Mark在图上。
并且保存在线上的点。

x = np.linspace(0,2,50)
y = rf + x * (rm - rf)
plt.figure(figsize=(16, 12))
plt.title('CAPM', fontsize = 18)
plt.ylim(0 , 0.4)
plt.xlim(0 , 2)
plt.ylabel('E(ri)')
plt.xlabel('Beta')
plt.plot(x,y, label = 'Security Market Line')
plt.scatter(0 , rf , label = 'Rf' , marker='*', color = 'orange', s = 28 ** 2)
#plt.plot(0 , rf , "yo", label = 'rf')
i = 0
portfolio = pd.DataFrame()
while(i<50):rd = random.randint(0 , len(stock_basic)+1)ri = pro.daily(ts_code=stock_basic.at[rd,'ts_code'] , start_date='20000101', end_date='20190901')beta = np.mean((ri['pct_chg'] - ri['pct_chg'].mean()) * (gzA['pct_chg'] - gzA['pct_chg'].mean())) / gzA['pct_chg'].std() ** 2x = betay = ri['pct_chg'].mean()if y > rf + x * (rm - rf):plt.scatter(x, y, marker='^', color = 'g')plt.annotate(stock_basic.at[rd,'ts_code'], xy = (x, y), xytext = (x+0.005, y+0.005))#portfolio_list[stock_basic.at[rd,'ts_code']] = stock_basic.at[rd,'name']portfolio[stock_basic.at[rd,'ts_code']] = ri['pct_chg'].head(100)else:plt.scatter(x, y, marker='o', color = 'r')plt.annotate(stock_basic.at[rd,'ts_code'], xy = (x, y), xytext = (x+0.005, y+0.005))i+=1
plt.legend()
plt.show()

output:

看一下保存下来股票的相关系数

#Corrilation of the portfolio
plt.figure(figsize=(16, 12))
sns.set_style("whitegrid")
sns.heatmap(portfolio.corr(), cmap='Blues', annot=False, vmin = 0.0, vmax = 1 ,linewidths=1 )

output:

根据收益率和相关性选取投组,选取规则是:
我们按照收益率对它们进行排序,将它们逐个放入my_portfolio_list,检查最后一只股票和下一只股票之间的相关性,如果它们的相关性大于0.3,那么我们将放弃选取下一个股票,获取下下一支股票,在检查两者相关性,以此类推。

my_portfolio_list = pd.DataFrame()
stock_mean = pd.DataFrame()
corr = portfolio.corr()
for stock in portfolio.columns:stock_mean.at[0,stock] = portfolio[stock].mean()
stock_mean = stock_mean.sort_values(0,ascending=False,axis = 1)
number = 0
for stock in stock_mean.columns:if number == 0:my_portfolio_list.at[0,stock] = stock_mean.at[0,stock]number += 1last = stockelse:if corr.at[stock,last]>0.3 or stock_mean.at[0,stock]<0:passelse:my_portfolio_list.at[0,stock] = stock_mean.at[0,stock]last = stock

my_portfolio_list的输出:
之后,就可以进行简单的投组可视化分析,例如收益率。

plt.figure(figsize=(20, 8))for p in my_portfolio_list.columns:daily_price = pro.daily(ts_code=p , start_date='20190101', end_date='20190901')daily_price = daily_price.sort_values('trade_date', ascending=True)date = pd.to_datetime(daily_price['trade_date'])plt.plot(date , daily_price['pct_chg'],label = p)
plt.legend()
plt.ylabel('Rate of Return')
plt.xlabel('Date')
#pl.xticks(rotation=50)
plt.title('The Rate of Return of My Portfolio', fontsize = 20)plt.show()

output:

设置完quantity之后可以看一下market value

quantity = 1000for p in my_portfolio_list.columns:my_portfolio_list.at[1,p] = quantityquantity -= 100
my_portfolio_list.index = ['pct_chg','quantity']
my_portfolio_list

output:

plt.figure(figsize=(10, 6))
for p in my_portfolio_list.columns:daily_price = pro.daily(ts_code=p , start_date='20190101', end_date='20190901')daily_price = daily_price.sort_values('trade_date', ascending=True)plt.plot(pd.to_datetime(daily_price['trade_date']), daily_price['open']*my_portfolio_list.at['quantity',p], label=p)
plt.title('Market Value of My Portfolio', fontsize=20)
plt.ylabel('Market Value')
plt.xlabel('Date')
plt.xticks(rotation=50)
plt.legend()
plt.show()

output:

Fama French Three-Factor Model

首先还是库的导入。

import tushare
import requests
import pandas as pd
import seaborn as sns
import statsmodels.api as sm
import numpy as np
from statsmodels import regression
import matplotlib.pyplot as plt
import timepro = tushare.pro_api('')

cal_smb_hml 函数,关于SMB、HML因子的计算。

def cal_smb_hml(stock_data):stock_data['SB'] = stock_data['circ_mv'].map(lambda x: 'B' if x >= stock_data['circ_mv'].median() else 'S')stock_data['BM'] = 1 / stock_data['pb']border_down, border_up = stock_data['BM'].quantile([0.3, 0.7])stock_data['HML'] = stock_data['BM'].map(lambda x: 'H' if x >= border_up else 'M')stock_data['HML'] = stock_data.apply(lambda row: 'L' if row['BM'] <= border_down else row['HML'], axis=1)stock_data_SL = stock_data.query('(SB=="S") & (HML=="L")')stock_data_SM = stock_data.query('(SB=="S") & (HML=="M")')stock_data_SH = stock_data.query('(SB=="S") & (HML=="H")')stock_data_BL = stock_data.query('(SB=="B") & (HML=="L")')stock_data_BM = stock_data.query('(SB=="B") & (HML=="M")')stock_data_BH = stock_data.query('(SB=="B") & (HML=="H")')R_SL = (stock_data_SL['pct_chg'] * stock_data_SL['circ_mv'] / 100).sum() / stock_data_SL['circ_mv'].sum()R_SM = (stock_data_SM['pct_chg'] * stock_data_SM['circ_mv'] / 100).sum() / stock_data_SM['circ_mv'].sum()R_SH = (stock_data_SH['pct_chg'] * stock_data_SH['circ_mv'] / 100).sum() / stock_data_SH['circ_mv'].sum()R_BL = (stock_data_BL['pct_chg'] * stock_data_BL['circ_mv'] / 100).sum() / stock_data_BL['circ_mv'].sum()R_BM = (stock_data_BM['pct_chg'] * stock_data_BM['circ_mv'] / 100).sum() / stock_data_BM['circ_mv'].sum()R_BH = (stock_data_BH['pct_chg'] * stock_data_BH['circ_mv'] / 100).sum() / stock_data_BH['circ_mv'].sum()smb = (R_SL + R_SM + R_SH - (R_BL + R_BM + R_BH)) / 3hml = (R_SH + R_BH -(R_SL + R_BL) ) / 2return smb, hml

get_data函数,获取相关数据。由于tushare权限不高,调用不能过于频繁,只能用try-except续命。

def get_data(st_d, ed_d):trade_calender = pro.trade_cal(start_date = st_d, end_date = ed_d)trade_calender =trade_calender.query('is_open==1')daily_data = pd.DataFrame()basic_data = pd.DataFrame()FF_data = pd.DataFrame(index = trade_calender['cal_date'], columns = ['Rm-Rf','SMB','HML','r_mean'])rf = 0.03064  # 3.064%for date in trade_calender['cal_date']:try:daily_data = pro.daily(trade_date = date)except:time.sleep(10)daily_data = pro.daily(trade_date = date)try:basic_data = pro.daily_basic(trade_date = date)except:time.sleep(10)basic_data = pro.daily_basic(trade_date = date)try:gzA = pro.index_daily(ts_code='399317.SZ', trade_date = date)except:time.sleep(10)gzA = pro.index_daily(ts_code='399317.SZ', trade_date = date)all_data = pd.merge(daily_data, basic_data, on='ts_code', how='inner')rm_rf = float((gzA['pct_chg']/100)-rf)smb, hml = cal_smb_hml(all_data)print(date , rm_rf , smb , hml)FF_data.at[date,'SMB'] = smbFF_data.at[date,'HML'] = hmlFF_data.at[date,'Rm-Rf'] = float(rm_rf)s = requests.session()s.keep_alive = Falsereturn FF_data

我们看一下获取近来五个月的数据的output:

FF_data表:

然后再导入一下CAPM中选取的投组:

把FF_data数据补全

for stk in my_portfolio.columns:dp = pro.daily(ts_code=stk, start_date='20190401', end_date='20190901')dp = dp.sort_values('trade_date', ascending=True)dp.index = dp['trade_date']FF_data[stk] = dp['pct_chg']/100
FF_data.head()
FF_data['r_mean'] = 0.0for d in FF_data.index:for stk in my_portfolio.columns:FF_data.at[d,'r_mean'] += my_portfolio.at[1, stk] /4000 * FF_data.at[d,stk]

output:

三个因子数据得到之后,同样可以做一些可视化分析。
相关性

sns.heatmap(FF_data.drop('cal_date',axis = 1).corr(), cmap='OrRd', annot=True)


收益率

import matplotlib.dates as dates
plt.figure(figsize=(24, 7))for p in FF_data.columns:plt.plot(FF_data.index,FF_data[p],label = p)
plt.legend()
plt.ylabel('Rate of Return')
plt.xlabel('Date')
plt.title('The Rate of Return of My Portfolio', fontsize = 20)
plt.xticks(rotation=70)plt.show()

output:

由于收益率有些混乱,我们只看一下三因子和投组的收益率。

FF_data = pd.read_csv('FFdata.csv')
FF_data.index = FF_data['cal_date']
FF_data = FF_data.drop('cal_date', axis = 1)
plt.figure(figsize=(24, 7))for p in FF_data.columns:if p == 'r_mean' or p == 'SMB' or p == 'HML' or p == 'Rm-Rf':plt.plot(FF_data.index,FF_data[p],label = p)else:pass
plt.legend()
plt.ylabel('Rate of Return')
plt.xlabel('Date')
plt.title('The Rate of Return of My Portfolio', fontsize = 20)
plt.xticks(rotation=70)
plt.xlim('2019-04-01' , '2019-09-01')plt.show()


最后十分重要的回归分析,这里用最小二乘法。

y = np.array((FF_data['r_mean']).astype(float))
y = y[1:len(y)]
Y = y.T
Rm_Rf = np.array(FF_data['Rm-Rf'].astype(float))
Rm_Rf = Rm_Rf[1:len(Rm_Rf)]
SMB = np.array((FF_data['SMB']).astype(float))
SMB = SMB[1:len(FF_data['SMB'])]
HMI = np.array((FF_data['HML']).astype(float))
HMI = HMI[1:len(FF_data['HML'])]
X = np.column_stack((Rm_Rf,SMB,HMI))
X = sm.add_constant(X)
model = sm.OLS(Y, X)
result = model.fit()result.summary()

output:

从结果来看,回归效果还不错。

总结

这只是一个非常简单的学习过程,本人不是金融专业,对股票市场还有待进一步了解,如有错误,麻烦大家多多指正。第一次写文章,有很多可以改进的地方,欢迎大家留言讨论。

用Python对CAPM和Fama French Three Factor model的初步学习相关推荐

  1. Fama—French五因子模型在中国股票市场适用吗?

    资产定价历来是金融经济学研究的核心问题.自Sharpe,Lintner,Treynor等于1964年提出资本资产定价模型(CAPM)以来,通过单一风险因素确定资产收益率受到理论和市场等多方面的挑战.为 ...

  2. 《Python编程:从入门到实战》(第2版)学习笔记 第5章 if语句

    [写在前面]为进一步提高自己的python代码能力,打算把几本经典书籍重新过一遍,形成系统的知识体系,同时适当记录一些学习笔记,我尽量及时更新!先从经典的<Python编程:从入门到实战> ...

  3. Python基于MASK信息抽取ROI子图并构建基于迁移学习(densenet)的图像分类器实战(原始影像和mask文件都是二维的情况)

    Python基于MASK信息抽取ROI子图并构建基于迁移学习(densenet)的图像分类器实战(原始影像和mask文件都是二维的情况) 目录

  4. python和java哪个好学、零基础-老男孩零基础学习|python和java那个更有发展前景?...

    python和java该如何选择?学习哪个更好呢?这对于很多人来说都是非常困扰的问题,也是很多IT从业者都比较关注的问题啊,很多人都知道python和java都是比较受欢迎的开发语言,目前在互联网上需 ...

  5. 适合自学python的图书-有哪些适合零编程基础的人学习Python的书?

    很多人在问,学习Python读什么书,这其实是一个非常通用的问题,学习分为三种方式:看书.上课.培训,而读书学习是最实惠也是最高效的一种,下面我们推荐6本高分书籍给大家,希望大家学习愉快: 1.Pyt ...

  6. c语言python零基础教学_编程零基础应当如何开始学习 Python?附教程

    零基础学编程,用python入门是个不错的选择,虽然国内基本上还是以c语言作为入门开发语言,但在国外,已经有很多的学校使用python作为入门编程语言.此外,python在机器学习,人工智能领域也非常 ...

  7. c语言python零基础教学_编程零基础应当如何开始学习 Python?

    目录 1.学习了解Python的基础知识. 2.安装Python,边学边练. 3.收集资料,作为练习指引. 4.确定学习方向,项目练手. 5.学习过程中要注意多练.多问! 编程零基础选择Python开 ...

  8. 从入门到入土:机器学习part02|python|初步学习|numpy|Matplotlib

    此博客仅用于记录个人学习进度,学识浅薄,若有错误观点欢迎评论区指出.欢迎各位前来交流.(部分材料来源网络,若有侵权,立即删除) 本人博客所有文章纯属学习之用,不涉及商业利益.不合适引用,自当删除! 若 ...

  9. 从入门到入土:机器学习part01|python|代码分析|初步学习

    此博客仅用于记录个人学习进度,学识浅薄,若有错误观点欢迎评论区指出.欢迎各位前来交流.(部分材料来源网络,若有侵权,立即删除) 本人博客所有文章纯属学习之用,不涉及商业利益.不合适引用,自当删除! 若 ...

最新文章

  1. python代码转换为pytorch_Pytorch中Tensor与各种图像格式的相互转化详解
  2. ActiveMQ的消息存储和持久化
  3. C++ trivial和non-trivial构造函数及POD类型(转)
  4. 省市区联动三级下拉列表实现
  5. ulimit问题 关于nproc设置
  6. MySQL索引和SQL调优手册
  7. vitamio 缓冲一部分时,loading还没消失,直接点击播放,loading未能消失
  8. 侯捷畅谈技术人生与读书感悟
  9. 12个国外免费DNS服务
  10. 太原科技大学主校区计算机学院,2021年太原科技大学有几个校区,大一新生在哪个校区...
  11. sql server 2000 打了sp4补丁包仍不能监听1433端口问题的解决
  12. java对文件进行md5加密,对文件进行 MD5 加密
  13. SHAPE 文件格式详解
  14. js闭包的理解以及闭包中this的理解
  15. 转 fpga学习经验2
  16. 课程设计——部门管理系统C++
  17. 使用pygame前的小插曲
  18. 没有基础能学会UI设计吗 有没有学习路线推荐
  19. IT人才市场最看重的12项技能
  20. 江苏机器人竞赛南航_南航金城学院学子在第十届江苏省机器人大赛中获佳绩

热门文章

  1. LWN: 回顾一下UMN 大学的那次事件!
  2. linux 系统修复模式
  3. leaflet调用2019天地图接口
  4. 如何在MathType中输入摄氏度符号
  5. C语言实验——逆置正整数 Time Limit: 1000 ms Memory Limit: 65536 KiB 1189
  6. 小程序跳转到另一个小程序,参数传递以及调试,H5跳转小程序,小程序内嵌H5,
  7. readv和writev
  8. 大数据平台的使用(Hadoop 生态圈、CDH)
  9. 布朗大学的机器人能一笔一划临摹出蒙娜丽莎,还能模仿你的笔迹
  10. 篇章级事件抽取任务拾遗