siat 3.10.132__py3-none-any.whl → 3.11.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- siat/__init__.py +0 -0
- siat/allin.py +8 -0
- siat/assets_liquidity.py +0 -0
- siat/beta_adjustment.py +0 -0
- siat/beta_adjustment_china.py +0 -0
- siat/blockchain.py +0 -0
- siat/bond.py +0 -0
- siat/bond_base.py +0 -0
- siat/bond_china.py +0 -0
- siat/bond_zh_sina.py +0 -0
- siat/capm_beta.py +0 -0
- siat/capm_beta2.py +4 -4
- siat/common.py +9 -6
- siat/compare_cross.py +0 -0
- siat/copyrights.py +0 -0
- siat/cryptocurrency.py +0 -0
- siat/economy.py +0 -0
- siat/economy2.py +0 -0
- siat/esg.py +0 -0
- siat/event_study.py +0 -0
- siat/exchange_bond_china.pickle +0 -0
- siat/fama_french.py +0 -0
- siat/fin_stmt2_yahoo.py +0 -0
- siat/financial_base.py +0 -0
- siat/financial_statements.py +0 -0
- siat/financials.py +0 -0
- siat/financials2.py +0 -0
- siat/financials_china.py +0 -0
- siat/financials_china2.py +0 -0
- siat/fund.py +0 -0
- siat/fund_china.pickle +0 -0
- siat/fund_china.py +0 -0
- siat/future_china.py +0 -0
- siat/google_authenticator.py +0 -0
- siat/grafix.py +55 -4
- siat/holding_risk.py +0 -0
- siat/luchy_draw.py +0 -0
- siat/market_china.py +0 -0
- siat/markowitz.py +0 -0
- siat/markowitz2.py +1 -0
- siat/markowitz2_20250704.py +0 -0
- siat/markowitz2_20250705.py +0 -0
- siat/markowitz_simple.py +0 -0
- siat/ml_cases.py +0 -0
- siat/ml_cases_example.py +0 -0
- siat/option_china.py +0 -0
- siat/option_pricing.py +0 -0
- siat/other_indexes.py +0 -0
- siat/risk_adjusted_return.py +0 -0
- siat/risk_adjusted_return2.py +8 -4
- siat/risk_evaluation.py +0 -0
- siat/risk_free_rate.py +0 -0
- siat/save2docx.py +345 -0
- siat/save2pdf.py +145 -0
- siat/sector_china.py +0 -0
- siat/security_price2.py +0 -0
- siat/security_prices.py +168 -6
- siat/security_trend.py +0 -0
- siat/security_trend2.py +2 -2
- siat/stock.py +11 -1
- siat/stock_advice_linear.py +0 -0
- siat/stock_base.py +0 -0
- siat/stock_china.py +0 -0
- siat/stock_info.pickle +0 -0
- siat/stock_prices_kneighbors.py +0 -0
- siat/stock_prices_linear.py +0 -0
- siat/stock_profile.py +0 -0
- siat/stock_technical.py +0 -0
- siat/stooq.py +0 -0
- siat/transaction.py +0 -0
- siat/translate.py +0 -0
- siat/valuation.py +0 -0
- siat/valuation_china.py +0 -0
- siat/var_model_validation.py +0 -0
- siat/yf_name.py +0 -0
- {siat-3.10.132.dist-info/licenses → siat-3.11.1.dist-info}/LICENSE +0 -0
- {siat-3.10.132.dist-info → siat-3.11.1.dist-info}/METADATA +234 -235
- siat-3.11.1.dist-info/RECORD +80 -0
- {siat-3.10.132.dist-info → siat-3.11.1.dist-info}/WHEEL +1 -1
- {siat-3.10.132.dist-info → siat-3.11.1.dist-info}/top_level.txt +0 -1
- build/lib/build/lib/siat/__init__.py +0 -75
- build/lib/build/lib/siat/allin.py +0 -137
- build/lib/build/lib/siat/assets_liquidity.py +0 -915
- build/lib/build/lib/siat/beta_adjustment.py +0 -1058
- build/lib/build/lib/siat/beta_adjustment_china.py +0 -548
- build/lib/build/lib/siat/blockchain.py +0 -143
- build/lib/build/lib/siat/bond.py +0 -2900
- build/lib/build/lib/siat/bond_base.py +0 -992
- build/lib/build/lib/siat/bond_china.py +0 -100
- build/lib/build/lib/siat/bond_zh_sina.py +0 -143
- build/lib/build/lib/siat/capm_beta.py +0 -783
- build/lib/build/lib/siat/capm_beta2.py +0 -887
- build/lib/build/lib/siat/common.py +0 -5360
- build/lib/build/lib/siat/compare_cross.py +0 -642
- build/lib/build/lib/siat/copyrights.py +0 -18
- build/lib/build/lib/siat/cryptocurrency.py +0 -667
- build/lib/build/lib/siat/economy.py +0 -1471
- build/lib/build/lib/siat/economy2.py +0 -1853
- build/lib/build/lib/siat/esg.py +0 -536
- build/lib/build/lib/siat/event_study.py +0 -815
- build/lib/build/lib/siat/fama_french.py +0 -1521
- build/lib/build/lib/siat/fin_stmt2_yahoo.py +0 -982
- build/lib/build/lib/siat/financial_base.py +0 -1160
- build/lib/build/lib/siat/financial_statements.py +0 -598
- build/lib/build/lib/siat/financials.py +0 -2339
- build/lib/build/lib/siat/financials2.py +0 -1278
- build/lib/build/lib/siat/financials_china.py +0 -4433
- build/lib/build/lib/siat/financials_china2.py +0 -2212
- build/lib/build/lib/siat/fund.py +0 -629
- build/lib/build/lib/siat/fund_china.py +0 -3307
- build/lib/build/lib/siat/future_china.py +0 -551
- build/lib/build/lib/siat/google_authenticator.py +0 -47
- build/lib/build/lib/siat/grafix.py +0 -3636
- build/lib/build/lib/siat/holding_risk.py +0 -867
- build/lib/build/lib/siat/luchy_draw.py +0 -638
- build/lib/build/lib/siat/market_china.py +0 -1168
- build/lib/build/lib/siat/markowitz.py +0 -2363
- build/lib/build/lib/siat/markowitz2.py +0 -3150
- build/lib/build/lib/siat/markowitz2_20250704.py +0 -2969
- build/lib/build/lib/siat/markowitz2_20250705.py +0 -3158
- build/lib/build/lib/siat/markowitz_simple.py +0 -373
- build/lib/build/lib/siat/ml_cases.py +0 -2291
- build/lib/build/lib/siat/ml_cases_example.py +0 -60
- build/lib/build/lib/siat/option_china.py +0 -3069
- build/lib/build/lib/siat/option_pricing.py +0 -1925
- build/lib/build/lib/siat/other_indexes.py +0 -409
- build/lib/build/lib/siat/risk_adjusted_return.py +0 -1576
- build/lib/build/lib/siat/risk_adjusted_return2.py +0 -1900
- build/lib/build/lib/siat/risk_evaluation.py +0 -2218
- build/lib/build/lib/siat/risk_free_rate.py +0 -351
- build/lib/build/lib/siat/sector_china.py +0 -4140
- build/lib/build/lib/siat/security_price2.py +0 -727
- build/lib/build/lib/siat/security_prices.py +0 -3408
- build/lib/build/lib/siat/security_trend.py +0 -402
- build/lib/build/lib/siat/security_trend2.py +0 -646
- build/lib/build/lib/siat/stock.py +0 -4284
- build/lib/build/lib/siat/stock_advice_linear.py +0 -934
- build/lib/build/lib/siat/stock_base.py +0 -26
- build/lib/build/lib/siat/stock_china.py +0 -2095
- build/lib/build/lib/siat/stock_prices_kneighbors.py +0 -910
- build/lib/build/lib/siat/stock_prices_linear.py +0 -386
- build/lib/build/lib/siat/stock_profile.py +0 -707
- build/lib/build/lib/siat/stock_technical.py +0 -3305
- build/lib/build/lib/siat/stooq.py +0 -74
- build/lib/build/lib/siat/transaction.py +0 -347
- build/lib/build/lib/siat/translate.py +0 -5183
- build/lib/build/lib/siat/valuation.py +0 -1378
- build/lib/build/lib/siat/valuation_china.py +0 -2076
- build/lib/build/lib/siat/var_model_validation.py +0 -444
- build/lib/build/lib/siat/yf_name.py +0 -811
- build/lib/siat/__init__.py +0 -75
- build/lib/siat/allin.py +0 -137
- build/lib/siat/assets_liquidity.py +0 -915
- build/lib/siat/beta_adjustment.py +0 -1058
- build/lib/siat/beta_adjustment_china.py +0 -548
- build/lib/siat/blockchain.py +0 -143
- build/lib/siat/bond.py +0 -2900
- build/lib/siat/bond_base.py +0 -992
- build/lib/siat/bond_china.py +0 -100
- build/lib/siat/bond_zh_sina.py +0 -143
- build/lib/siat/capm_beta.py +0 -783
- build/lib/siat/capm_beta2.py +0 -887
- build/lib/siat/common.py +0 -5360
- build/lib/siat/compare_cross.py +0 -642
- build/lib/siat/copyrights.py +0 -18
- build/lib/siat/cryptocurrency.py +0 -667
- build/lib/siat/economy.py +0 -1471
- build/lib/siat/economy2.py +0 -1853
- build/lib/siat/esg.py +0 -536
- build/lib/siat/event_study.py +0 -815
- build/lib/siat/fama_french.py +0 -1521
- build/lib/siat/fin_stmt2_yahoo.py +0 -982
- build/lib/siat/financial_base.py +0 -1160
- build/lib/siat/financial_statements.py +0 -598
- build/lib/siat/financials.py +0 -2339
- build/lib/siat/financials2.py +0 -1278
- build/lib/siat/financials_china.py +0 -4433
- build/lib/siat/financials_china2.py +0 -2212
- build/lib/siat/fund.py +0 -629
- build/lib/siat/fund_china.py +0 -3307
- build/lib/siat/future_china.py +0 -551
- build/lib/siat/google_authenticator.py +0 -47
- build/lib/siat/grafix.py +0 -3636
- build/lib/siat/holding_risk.py +0 -867
- build/lib/siat/luchy_draw.py +0 -638
- build/lib/siat/market_china.py +0 -1168
- build/lib/siat/markowitz.py +0 -2363
- build/lib/siat/markowitz2.py +0 -3150
- build/lib/siat/markowitz2_20250704.py +0 -2969
- build/lib/siat/markowitz2_20250705.py +0 -3158
- build/lib/siat/markowitz_simple.py +0 -373
- build/lib/siat/ml_cases.py +0 -2291
- build/lib/siat/ml_cases_example.py +0 -60
- build/lib/siat/option_china.py +0 -3069
- build/lib/siat/option_pricing.py +0 -1925
- build/lib/siat/other_indexes.py +0 -409
- build/lib/siat/risk_adjusted_return.py +0 -1576
- build/lib/siat/risk_adjusted_return2.py +0 -1900
- build/lib/siat/risk_evaluation.py +0 -2218
- build/lib/siat/risk_free_rate.py +0 -351
- build/lib/siat/sector_china.py +0 -4140
- build/lib/siat/security_price2.py +0 -727
- build/lib/siat/security_prices.py +0 -3408
- build/lib/siat/security_trend.py +0 -402
- build/lib/siat/security_trend2.py +0 -646
- build/lib/siat/stock.py +0 -4284
- build/lib/siat/stock_advice_linear.py +0 -934
- build/lib/siat/stock_base.py +0 -26
- build/lib/siat/stock_china.py +0 -2095
- build/lib/siat/stock_prices_kneighbors.py +0 -910
- build/lib/siat/stock_prices_linear.py +0 -386
- build/lib/siat/stock_profile.py +0 -707
- build/lib/siat/stock_technical.py +0 -3305
- build/lib/siat/stooq.py +0 -74
- build/lib/siat/transaction.py +0 -347
- build/lib/siat/translate.py +0 -5183
- build/lib/siat/valuation.py +0 -1378
- build/lib/siat/valuation_china.py +0 -2076
- build/lib/siat/var_model_validation.py +0 -444
- build/lib/siat/yf_name.py +0 -811
- siat-3.10.132.dist-info/RECORD +0 -218
@@ -1,783 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
"""
|
3
|
-
本模块功能:CAPM模型贝塔系数计算
|
4
|
-
所属工具包:证券投资分析工具SIAT
|
5
|
-
SIAT:Security Investment Analysis Tool
|
6
|
-
创建日期:2018年7月16日
|
7
|
-
最新修订日期:2020年1月15日
|
8
|
-
作者:王德宏 (WANG Dehong, Peter)
|
9
|
-
作者单位:北京外国语大学国际商学院
|
10
|
-
作者邮件:wdehong2000@163.com
|
11
|
-
版权所有:王德宏
|
12
|
-
用途限制:仅限研究与教学使用,不可商用!商用需要额外授权。
|
13
|
-
特别声明:作者不对使用本工具进行证券投资导致的任何损益负责!
|
14
|
-
"""
|
15
|
-
|
16
|
-
#==============================================================================
|
17
|
-
import warnings; warnings.filterwarnings('ignore')
|
18
|
-
from siat.common import *
|
19
|
-
from siat.translate import *
|
20
|
-
from siat.security_prices import *
|
21
|
-
from siat.security_price2 import *
|
22
|
-
#==============================================================================
|
23
|
-
import matplotlib.pyplot as plt
|
24
|
-
|
25
|
-
#处理绘图汉字乱码问题
|
26
|
-
import sys; czxt=sys.platform
|
27
|
-
if czxt in ['win32','win64']:
|
28
|
-
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置默认字体
|
29
|
-
mpfrc={'font.family': 'SimHei'}
|
30
|
-
|
31
|
-
if czxt in ['darwin']: #MacOSX
|
32
|
-
plt.rcParams['font.family']= ['Heiti TC']
|
33
|
-
mpfrc={'font.family': 'Heiti TC'}
|
34
|
-
|
35
|
-
if czxt in ['linux']: #website Jupyter
|
36
|
-
plt.rcParams['font.family']= ['Heiti TC']
|
37
|
-
mpfrc={'font.family':'Heiti TC'}
|
38
|
-
|
39
|
-
# 解决保存图像时'-'显示为方块的问题
|
40
|
-
plt.rcParams['axes.unicode_minus'] = False
|
41
|
-
#==============================================================================
|
42
|
-
def get_price_excel(ticker,fromdate,todate,excelfile,sheetname='Sheet1'):
|
43
|
-
"""
|
44
|
-
功能:抓取股价,保存到Excel文件中
|
45
|
-
输出:指定收盘价格序列,最新日期的股价排列在前
|
46
|
-
ticker: 股票代码。大陆股票代码加上后缀.SZ或.SS,港股代码去掉前导0加后缀.HK
|
47
|
-
fromdate: 样本开始日期,尽量远的日期,以便取得足够多的原始样本
|
48
|
-
todate: 样本结束日期,既可以是今天日期,也可以是一个历史日期
|
49
|
-
excelfile:保存到Excel文件名,含目录。如果目录不存在,将会导致错误。
|
50
|
-
"""
|
51
|
-
|
52
|
-
#仅为调试用的函数入口参数,正式使用前需要注释掉!
|
53
|
-
#ticker='000300.SS'
|
54
|
-
#fromdate='01/01/2018'
|
55
|
-
#todate='06/30/2019'
|
56
|
-
#---------------------------------------------
|
57
|
-
|
58
|
-
#仅为测试使用
|
59
|
-
#ticker='601857.SS'
|
60
|
-
#fromdate='2019-1-1'
|
61
|
-
#todate='2019-8-31'
|
62
|
-
#excelfile='C:/temp/myexcel1.xlsx'
|
63
|
-
#sheetname='601857.SS'
|
64
|
-
|
65
|
-
price=get_price(ticker,fromdate,todate)
|
66
|
-
if price is None:
|
67
|
-
print(" #Error(get_price_excel): failed to retrieve stock data")
|
68
|
-
print(" Information:",ticker,fromdate,todate)
|
69
|
-
return
|
70
|
-
try:
|
71
|
-
price.to_excel(excelfile,sheetname,encoding='utf-8')
|
72
|
-
except:
|
73
|
-
print(" #Error((get_price_excel): failed to stock data to excel file")
|
74
|
-
print(" Information:",excelfile,sheetname)
|
75
|
-
return
|
76
|
-
print("***Results saved in",excelfile,"with sheet",sheetname)
|
77
|
-
return
|
78
|
-
|
79
|
-
|
80
|
-
if __name__=='__main__':
|
81
|
-
df601857=get_price_excel('601857.SS','2019-1-1','2019-12-31', \
|
82
|
-
'C:/temp/myexcel1.xlsx','601857.SS')
|
83
|
-
|
84
|
-
|
85
|
-
#==============================================================================
|
86
|
-
def prepare_capm_data(stkcd,mktidx,start,end):
|
87
|
-
"""
|
88
|
-
函数功能:准备计算一只股票CAPM模型贝塔系数的数据,并标记年度
|
89
|
-
输入参数:
|
90
|
-
stkcd: 股票代码
|
91
|
-
mktidx: 指数代码
|
92
|
-
start:使用股票价格数据的开始日期,MM/DD/YYYY
|
93
|
-
end:使用股票价格数据的结束日期,MM/DD/YYYY
|
94
|
-
输出数据:
|
95
|
-
返回数据:带年度标记的可直接用于capm回归的股票收益率数据
|
96
|
-
"""
|
97
|
-
|
98
|
-
#仅用于调试,正式使用前应注释掉
|
99
|
-
#stkcd='600028.SS'; mktidx='000001.SS'
|
100
|
-
#start="12/31/2011"; end="12/31/2018"
|
101
|
-
|
102
|
-
#抓取股价和指数
|
103
|
-
import siat.security_prices as ssp
|
104
|
-
stock=get_price(stkcd,start,end)
|
105
|
-
if stock is None:
|
106
|
-
print(" #Error(prepare_capm_data): failed to get stock price")
|
107
|
-
print(" Information:",stkcd,start,end)
|
108
|
-
return None
|
109
|
-
market=get_price(mktidx,start,end)
|
110
|
-
if market is None:
|
111
|
-
print(" #Error(prepare_capm_data): failed to get market index")
|
112
|
-
print(" Information:",mktidx,start,end)
|
113
|
-
return None
|
114
|
-
|
115
|
-
#计算日收益率
|
116
|
-
import pandas as pd
|
117
|
-
stkret=pd.DataFrame(stock['Close'].pct_change())
|
118
|
-
mktret=pd.DataFrame(market['Close'].pct_change())
|
119
|
-
|
120
|
-
#合并,去掉空缺
|
121
|
-
R=pd.merge(mktret,stkret,how='left',left_index=True,right_index=True)
|
122
|
-
R=R.dropna()
|
123
|
-
|
124
|
-
#标记各个年度
|
125
|
-
R['Year']=R.index.strftime("%Y")
|
126
|
-
|
127
|
-
#返回带年份的股票收益率序列
|
128
|
-
return R
|
129
|
-
|
130
|
-
#==============================================================================
|
131
|
-
def capm_beta(ticker,mktidx,start,end='today'):
|
132
|
-
"""
|
133
|
-
函数功能:计算一只股票的静态CAPM模型贝塔系数
|
134
|
-
输入参数:
|
135
|
-
ticker: 股票代码
|
136
|
-
mktidx: 指数代码
|
137
|
-
start:使用股票价格数据的开始日期,MM/DD/YYYY
|
138
|
-
end:使用股票价格数据的结束日期,MM/DD/YYYY
|
139
|
-
输出数据:
|
140
|
-
显示CAPM市场模型回归的alpha, beta, 以及显著性和拟合优度
|
141
|
-
无返回数据
|
142
|
-
"""
|
143
|
-
start,end=start_end_preprocess(start,end)
|
144
|
-
|
145
|
-
#读取股价并准备好收益率数据
|
146
|
-
R=prepare_capm_data(ticker,mktidx,start,end)
|
147
|
-
if R is None:
|
148
|
-
print(" #Error(capm_beta): failed to prepare capm data")
|
149
|
-
print(" Info:",ticker,mktidx,start,end)
|
150
|
-
return
|
151
|
-
|
152
|
-
#全数据OLS回归
|
153
|
-
from scipy import stats
|
154
|
-
(beta,alpha,r_value,p_value,std_err)= \
|
155
|
-
stats.linregress(R['Close_x'],R['Close_y'])
|
156
|
-
|
157
|
-
#显示回归结果
|
158
|
-
print(" \n===== 计算CAPM贝塔系数 =====")
|
159
|
-
print("回归模型:市场模型")
|
160
|
-
print(equalwidth("股票",16), ticker_name(ticker))
|
161
|
-
print(equalwidth("市场指数",16), ticker_name(mktidx))
|
162
|
-
print(equalwidth("样本期间开始于",16), start)
|
163
|
-
print(equalwidth("样本期间结束于",16), end)
|
164
|
-
print(equalwidth("截距项",16), round(alpha,4))
|
165
|
-
print(equalwidth("贝塔系数",16), round(beta,4))
|
166
|
-
print(equalwidth("R-square",16), round(r_value**2,4))
|
167
|
-
print(equalwidth("p-value",16), round(p_value,4))
|
168
|
-
|
169
|
-
import datetime
|
170
|
-
today = datetime.date.today()
|
171
|
-
print("*数据来源: 新浪/stooq/fred,",today)
|
172
|
-
|
173
|
-
return beta
|
174
|
-
|
175
|
-
if __name__=='__main__':
|
176
|
-
capm_beta('002504.SZ','000001.SS','12/31/2011','12/31/2018')
|
177
|
-
|
178
|
-
#==============================================================================
|
179
|
-
|
180
|
-
def plot_trend(titletxt,footnotetxt,df,power=1,axhline_value=1,axhline_label=''):
|
181
|
-
"""
|
182
|
-
功能:绘制散点数据的平滑曲线图及其趋势线
|
183
|
-
titletxt: 标题
|
184
|
-
footnotetxt:脚注
|
185
|
-
df: 数据框,其索引为字符型年份,第1列与年份对应的数值1,
|
186
|
-
第2列与年份对应的数值2,。。。
|
187
|
-
power: 趋势线拟合的幂阶数,默认为三阶多项式
|
188
|
-
"""
|
189
|
-
#将字符型年份转化为整数型
|
190
|
-
yearstr=df.index
|
191
|
-
year=[]
|
192
|
-
for t in yearstr:
|
193
|
-
tt=int(t)
|
194
|
-
year=year+[tt]
|
195
|
-
|
196
|
-
#取得列名
|
197
|
-
rowlist=df.columns.values.tolist()
|
198
|
-
n=len(rowlist)
|
199
|
-
|
200
|
-
import numpy as np
|
201
|
-
import scipy.interpolate as itp
|
202
|
-
|
203
|
-
#由于年度为连续整数,为插值方便,先将所有年度放大10倍
|
204
|
-
year0=[]
|
205
|
-
for t in year:
|
206
|
-
tt=t*10
|
207
|
-
year0=year0+[tt]
|
208
|
-
|
209
|
-
#形成用于插值的连续整数自变量xx
|
210
|
-
x1=year0[0]
|
211
|
-
x2=year0[-1]+1
|
212
|
-
xx=np.array(range(x1,x2,1))
|
213
|
-
|
214
|
-
#将用于插值的自变量缩小10倍,以便自变量在x轴上的尺度统一
|
215
|
-
x=[]
|
216
|
-
for t in xx:
|
217
|
-
tt=t/10.0
|
218
|
-
x=x+[tt]
|
219
|
-
|
220
|
-
#循环处理每个因变量
|
221
|
-
for i in np.array(range(0,n,1)):
|
222
|
-
number=df[rowlist[i]]
|
223
|
-
|
224
|
-
#进行插值: linear=线性插值, cubic=立方插值
|
225
|
-
y=itp.interp1d(year0,number,kind='cubic')
|
226
|
-
#生成插值出来的模拟数据因变量
|
227
|
-
y2=y(xx)
|
228
|
-
#绘图1:插值出来的大量模拟点构成的平滑曲线
|
229
|
-
plt.plot(x,y2)
|
230
|
-
#绘图2:原数据点
|
231
|
-
|
232
|
-
#进行拟合: 1=线性拟合, 2=二次拟合,3=三次拟合
|
233
|
-
p=np.polyfit(year0,number,power)
|
234
|
-
#生成拟合出来的模拟数据因变量
|
235
|
-
p2=np.polyval(p,xx)
|
236
|
-
#绘图2:拟合出来的大量模拟点构成的平滑趋势曲线
|
237
|
-
plt.plot(x,p2,linestyle=':',linewidth=3)
|
238
|
-
|
239
|
-
#绘图3:原数据点
|
240
|
-
plt.plot(year,number,'*',label=rowlist[i])
|
241
|
-
|
242
|
-
#是否绘制水平线
|
243
|
-
if axhline_label !="":
|
244
|
-
if '市场' in axhline_label:
|
245
|
-
axhline_label=''
|
246
|
-
plt.axhline(y=axhline_value,label=axhline_label,color='black',linestyle=':',linewidth=2)
|
247
|
-
#plt.axhline(y=axhline_value,color='purple',linestyle=':',linewidth=1.5)
|
248
|
-
|
249
|
-
#x轴刻度:使用原数据点的自变量
|
250
|
-
plt.xticks(year,rotation=30)
|
251
|
-
plt.legend(loc='best')
|
252
|
-
plt.title(titletxt)
|
253
|
-
plt.xlabel(footnotetxt)
|
254
|
-
|
255
|
-
plt.gca().set_facecolor('whitesmoke')
|
256
|
-
plt.show()
|
257
|
-
|
258
|
-
return
|
259
|
-
#==============================================================================
|
260
|
-
|
261
|
-
def capm_beta_yearly(ticker,mktidx,yearlist):
|
262
|
-
"""
|
263
|
-
函数功能:分年度计算一只股票的CAPM模型贝塔系数
|
264
|
-
输入参数:
|
265
|
-
ticker: 股票代码
|
266
|
-
mktidx: 指数代码
|
267
|
-
yearlist: 年度列表,start日期要给第一个年份留出至少一年数据供回归使用
|
268
|
-
输出数据:
|
269
|
-
按年份显示CAPM市场模型回归的alpha, beta, 以及显著性和拟合优度
|
270
|
-
无返回数据
|
271
|
-
"""
|
272
|
-
|
273
|
-
#运行开始信息
|
274
|
-
print("*** Analysing yearly CAPM betas, please wait ...")
|
275
|
-
|
276
|
-
#生成开始结束日期
|
277
|
-
Y4=str(int(yearlist[0])-1)
|
278
|
-
start=Y4+'-01-01'
|
279
|
-
end=yearlist[-1]+'-12-31'
|
280
|
-
|
281
|
-
#读取股价并准备好收益率数据
|
282
|
-
R=prepare_capm_data(ticker,mktidx,start,end)
|
283
|
-
if R is None:
|
284
|
-
print(" #Error(capm_beta_yearly): failed to prepare capm data")
|
285
|
-
print(" Information:",ticker,mktidx,start,end)
|
286
|
-
return
|
287
|
-
|
288
|
-
#print("\n***CAPM yearly beta: Stock_return=alpha+beta*Market_return")
|
289
|
-
#print("Stock code:",ticker)
|
290
|
-
#print("Market index:",mktidx)
|
291
|
-
#print("Year Beta R-sqr p-value")
|
292
|
-
|
293
|
-
#用于保存beta(CAPM)
|
294
|
-
import pandas as pd
|
295
|
-
betas=pd.DataFrame(columns=('Year','Beta','alpha','R-sqr','p-value'))
|
296
|
-
|
297
|
-
#分年度OLS回归
|
298
|
-
from scipy import stats
|
299
|
-
for year in yearlist:
|
300
|
-
#print(year,' ',end='')
|
301
|
-
r=R[R['Year']==year]
|
302
|
-
if len(r)==0: continue
|
303
|
-
try:
|
304
|
-
output=stats.linregress(r['Close_x'],r['Close_y'])
|
305
|
-
except:
|
306
|
-
print(" #Error(capm_beta_yearly): no data for regression")
|
307
|
-
print(" Information:",stkcd,year,R,r)
|
308
|
-
return
|
309
|
-
(beta,alpha,r_value,p_value,std_err)=output
|
310
|
-
|
311
|
-
row=pd.Series({'Year':year,'Beta':beta,'alpha':alpha, \
|
312
|
-
'R-sqr':r_value**2,'p-value':p_value})
|
313
|
-
try:
|
314
|
-
betas=betas.append(row,ignore_index=True)
|
315
|
-
except:
|
316
|
-
betas=betas._append(row,ignore_index=True)
|
317
|
-
#print(year,round(beta,4),round(r_value**2,3),round(p_value,4))
|
318
|
-
|
319
|
-
betas['Significance']=betas['p-value'].apply(lambda x: '***' if x<0.01 \
|
320
|
-
else '**' if x<0.05 else '*' if x<0.1 else '')
|
321
|
-
|
322
|
-
#设置打印标题与数据对齐
|
323
|
-
"""
|
324
|
-
pd.set_option('display.unicode.ambiguous_as_wide', True)
|
325
|
-
pd.set_option('display.unicode.east_asian_width', True)
|
326
|
-
pd.set_option('display.width', 180) # 设置打印宽度(**重要**)
|
327
|
-
|
328
|
-
print("\n ===== 分年度静态贝塔系数:",ticker_name(ticker),"=====")
|
329
|
-
print(betas.to_string(index=False))
|
330
|
-
import datetime as dt; todaydt=dt.date.today()
|
331
|
-
print("数据来源:新浪/stooq/fred,基于"+ticker_name(mktidx)+','+str(dttoday))
|
332
|
-
print('') #空一行
|
333
|
-
"""
|
334
|
-
titletxt="分年度静态贝塔系数: "+ticker_name(ticker)
|
335
|
-
import datetime as dt; todaydt=dt.date.today()
|
336
|
-
footnote="数据来源:新浪/stooq/fred,基于"+ticker_name(mktidx)+', '+str(todaydt)
|
337
|
-
df_display_CSS(betas,titletxt=titletxt,footnote=footnote,facecolor='papayawhip', \
|
338
|
-
decimals=4, \
|
339
|
-
first_col_align='center',second_col_align='center', \
|
340
|
-
last_col_align='center',other_col_align='center')
|
341
|
-
|
342
|
-
#准备绘图
|
343
|
-
betas.set_index('Year',inplace=True)
|
344
|
-
|
345
|
-
#绘图:年度贝塔系数趋势
|
346
|
-
df=pd.DataFrame(betas['Beta'])
|
347
|
-
title="分年度静态贝塔系数: "+ticker_name(ticker)
|
348
|
-
foot="\n数据来源:新浪/stooq/fred,基于"+ticker_name(mktidx)+','+str(todaydt)
|
349
|
-
plot_trend(title,foot,df,power=3,axhline_value=1,axhline_label='市场风险线')
|
350
|
-
|
351
|
-
return betas
|
352
|
-
|
353
|
-
if __name__=='__main__':
|
354
|
-
yearlist=['2013','2014','2015','2016','2017','2018','2019']
|
355
|
-
capm_beta_yearly('AAPL','^GSPC',yearlist)
|
356
|
-
|
357
|
-
#==============================================================================
|
358
|
-
#新增投资组合贝塔系数部分
|
359
|
-
#==============================================================================
|
360
|
-
#==============================================================================
|
361
|
-
def prepare_capm_portfolio(tickerlist,sharelist,mktidx,start,end):
|
362
|
-
"""
|
363
|
-
函数功能:准备计算股票投资组合CAPM模型贝塔系数的数据,并标记年度
|
364
|
-
输入参数:
|
365
|
-
tickerlist: 股票代码列表
|
366
|
-
sharelist:持有份额列表
|
367
|
-
mktidx: 市场指数代码
|
368
|
-
start:使用股票价格数据的开始日期,'YYYY-MM-DD'
|
369
|
-
end:使用股票价格数据的结束日期
|
370
|
-
输出数据:
|
371
|
-
返回数据:带年度标记的可直接用于capm模型回归的数据表
|
372
|
-
"""
|
373
|
-
|
374
|
-
#仅用于调试,正式使用前应注释掉
|
375
|
-
#tickerlist=['AAPL','MSFT']
|
376
|
-
#sharelist=[2,1]
|
377
|
-
#mktidx='^GSPC'
|
378
|
-
#start="1/1/2019"; end="8/31/2019"
|
379
|
-
|
380
|
-
#抓取投资组合股价和指数
|
381
|
-
import siat.security_prices as ssp
|
382
|
-
stock=get_price_portfolio(tickerlist,sharelist,start,end)
|
383
|
-
if (stock is None) or (len(stock)==0):
|
384
|
-
print(" #Error(prepare_capm_portfolio): failed to get stock prices")
|
385
|
-
print(" Info:",tickerlist,start,end)
|
386
|
-
return None
|
387
|
-
market=get_price(mktidx,start,end)
|
388
|
-
if (market is None) or (len(market)==0):
|
389
|
-
print(" #Error(prepare_capm_portfolio): failed to get market index")
|
390
|
-
print(" Info:",mktidx,start,end)
|
391
|
-
return None
|
392
|
-
|
393
|
-
#计算日收益率
|
394
|
-
import pandas as pd
|
395
|
-
stkret=pd.DataFrame(stock['Close'].pct_change())
|
396
|
-
mktret=pd.DataFrame(market['Close'].pct_change())
|
397
|
-
|
398
|
-
#合并:mktret作为Close_x,stkret作为Close_y,去掉空缺
|
399
|
-
R=pd.merge(mktret,stkret,how='left',left_index=True,right_index=True)
|
400
|
-
R=R.dropna()
|
401
|
-
|
402
|
-
#标记各个年度
|
403
|
-
R['Year']=R.index.strftime("%Y")
|
404
|
-
|
405
|
-
#返回带年份的股票收益率序列
|
406
|
-
return R
|
407
|
-
|
408
|
-
#==============================================================================
|
409
|
-
def capm_beta_portfolio(tickerlist,sharelist,mktidx,start,end):
|
410
|
-
"""
|
411
|
-
函数功能:计算投资组合的静态CAPM模型贝塔系数
|
412
|
-
输入参数:
|
413
|
-
tickerlist: 股票代码列表
|
414
|
-
sharelist:持有份额列表
|
415
|
-
mktidx: 指数代码
|
416
|
-
start:使用股票价格数据的开始日期,MM/DD/YYYY
|
417
|
-
end:使用股票价格数据的结束日期,MM/DD/YYYY
|
418
|
-
输出数据:
|
419
|
-
显示CAPM市场模型回归的截距, beta, 以及显著性和拟合优度
|
420
|
-
无返回数据
|
421
|
-
"""
|
422
|
-
|
423
|
-
#读取股价并准备好收益率数据
|
424
|
-
R=prepare_capm_portfolio(tickerlist,sharelist,mktidx,start,end)
|
425
|
-
if R is None:
|
426
|
-
print(" #Error(capm_beta_portfolio): failed to prepare capm data")
|
427
|
-
print(" Information:",tickerlist,sharelist,mktidx,start,end)
|
428
|
-
return
|
429
|
-
|
430
|
-
#全数据OLS回归
|
431
|
-
from scipy import stats
|
432
|
-
(beta,alpha,r_value,p_value,std_err)= \
|
433
|
-
stats.linregress(R['Close_x'],R['Close_y'])
|
434
|
-
|
435
|
-
#显示回归结果
|
436
|
-
print("\n *** Portfolio CAPM Beta Coefficient \
|
437
|
-
\n Model: Stock_return=intercept + beta * Market_return")
|
438
|
-
print(" Portfolio stocks:",tickerlist)
|
439
|
-
print(" Stock portions :",sharelist)
|
440
|
-
print(" Market index :",mktidx)
|
441
|
-
print(" Intercept :",round(alpha,4))
|
442
|
-
print(" Portfolio beta :",round(beta,4))
|
443
|
-
print(" R-sqr :",round(r_value**2,4))
|
444
|
-
print(" p-value :",round(p_value,4))
|
445
|
-
|
446
|
-
return beta
|
447
|
-
|
448
|
-
|
449
|
-
#==============================================================================
|
450
|
-
def capm_beta_portfolio_yearly(tickerlist,sharelist,mktidx,yearlist):
|
451
|
-
"""
|
452
|
-
函数功能:分年度计算投资组合的CAPM模型贝塔系数,并绘图
|
453
|
-
输入参数:
|
454
|
-
tickerlist: 投资组合中各个成分股的股票代码
|
455
|
-
sharelist: 各个成分股的持股比例
|
456
|
-
mktidx: 指数代码
|
457
|
-
yearlist: 年度列表,start日期要给第一个年份留出至少一年数据供回归使用
|
458
|
-
输出数据:
|
459
|
-
按年份绘图beta
|
460
|
-
无返回数据
|
461
|
-
"""
|
462
|
-
|
463
|
-
#运行开始信息
|
464
|
-
print("*** Analysing yearly portfolio CAPM betas, please wait ...")
|
465
|
-
|
466
|
-
#生成开始结束日期
|
467
|
-
Y4=str(int(yearlist[0])-1)
|
468
|
-
start=Y4+'-01-01'
|
469
|
-
end=yearlist[-1]+'-12-31'
|
470
|
-
|
471
|
-
#读取股价并准备好收益率数据
|
472
|
-
R=prepare_capm_portfolio(tickerlist,sharelist,mktidx,start,end)
|
473
|
-
if (R is None) or (len(R)==0):
|
474
|
-
print(" #Error(capm_beta_portfolio_yearly): failed to prepare capm data")
|
475
|
-
print(" Info:",tickerlist,sharelist,mktidx,start,end)
|
476
|
-
return
|
477
|
-
|
478
|
-
#用于保存beta(CAPM)和beta
|
479
|
-
import pandas as pd
|
480
|
-
betas=pd.DataFrame(columns=('Year','Beta','intercept','R-sqr','p-value'))
|
481
|
-
|
482
|
-
#分年度OLS回归
|
483
|
-
from scipy import stats
|
484
|
-
for year in yearlist:
|
485
|
-
#print(year,' ',end='')
|
486
|
-
r=R[R['Year']==year]
|
487
|
-
if len(r)==0: continue
|
488
|
-
try:
|
489
|
-
output=stats.linregress(r['Close_x'],r['Close_y'])
|
490
|
-
except:
|
491
|
-
print(" #Error(capm_beta_portfolio_yearly): no data for regression")
|
492
|
-
print(" Information:",year,R,r)
|
493
|
-
return
|
494
|
-
(beta,alpha,r_value,p_value,std_err)=output
|
495
|
-
|
496
|
-
row=pd.Series({'Year':year,'Beta':beta,'intercept':alpha, \
|
497
|
-
'R-sqr':r_value**2,'p-value':p_value})
|
498
|
-
try:
|
499
|
-
betas=betas.append(row,ignore_index=True)
|
500
|
-
except:
|
501
|
-
betas=betas._append(row,ignore_index=True)
|
502
|
-
|
503
|
-
betas['Significance']=betas['p-value'].apply(lambda x: '***' if x<0.01 \
|
504
|
-
else '**' if x<0.05 else '*' if x<0.1 else '')
|
505
|
-
#print("\n",betas)
|
506
|
-
|
507
|
-
titletxt="投资组合的静态年度贝塔系数"
|
508
|
-
import datetime as dt; todaydt=dt.date.today()
|
509
|
-
footnote="数据来源:新浪/stooq/fred,基于"+ticker_name(mktidx)+', '+str(todaydt)
|
510
|
-
df_display_CSS(betas,titletxt=titletxt,footnote=footnote,facecolor='papayawhip', \
|
511
|
-
decimals=4, \
|
512
|
-
first_col_align='center',second_col_align='center', \
|
513
|
-
last_col_align='center',other_col_align='center')
|
514
|
-
|
515
|
-
betas.set_index('Year',inplace=True)
|
516
|
-
|
517
|
-
#绘图:年度贝塔系数变化
|
518
|
-
df=pd.DataFrame(betas['Beta'])
|
519
|
-
title="投资组合的静态年度贝塔系数"+ \
|
520
|
-
"\n成分股: "+str(ticker_name(tickerlist,'bond'))+"\n持仓权重: "+str(sharelist)
|
521
|
-
import datetime; today = datetime.date.today()
|
522
|
-
foot="数据来源: 新浪/stooq/fred,"+str(today)
|
523
|
-
plot_trend(title,foot,df,power=2,axhline_value=1,axhline_label='市场风险线')
|
524
|
-
|
525
|
-
return betas
|
526
|
-
|
527
|
-
if __name__=='__main__':
|
528
|
-
yearlist=['2013','2014','2015','2016','2017','2018','2019']
|
529
|
-
capm_beta_portfolio_yearly(['AAPL','MSFT'],[2,1],'^GSPC',yearlist)
|
530
|
-
capm_beta_portfolio_yearly(['600028.SS','600036.SS'],[2,1],'000001.SS',yearlist)
|
531
|
-
|
532
|
-
#==============================================================================
|
533
|
-
def capm_beta_portfolio_yearly_excel(tickerlist,sharelist,mktidx,yearlist, \
|
534
|
-
excelfile,sheetname='Sheet1'):
|
535
|
-
"""
|
536
|
-
函数功能:分年度计算投资组合的CAPM模型贝塔系数,绘图,结果保存到Excel
|
537
|
-
输入参数:
|
538
|
-
tickerlist: 投资组合中各个成分股的股票代码
|
539
|
-
sharelist: 各个成分股的持股比例
|
540
|
-
mktidx: 指数代码
|
541
|
-
yearlist: 年度列表
|
542
|
-
excelfile: 带目录的Excel文件名,如果目录不存在则出错
|
543
|
-
sheetname:Excel文件中的sheet名
|
544
|
-
输出:
|
545
|
-
按年份绘图beta系数, 并保存到Excel文件
|
546
|
-
无返回数据
|
547
|
-
"""
|
548
|
-
|
549
|
-
#运行开始信息
|
550
|
-
print("\n*** Analysing yearly portfolio CAPM betas, please wait ...")
|
551
|
-
|
552
|
-
#生成开始结束日期
|
553
|
-
Y4=str(int(yearlist[0])-1)
|
554
|
-
start=Y4+'-01-01'
|
555
|
-
end=yearlist[-1]+'-12-31'
|
556
|
-
|
557
|
-
#读取股价并准备好收益率数据
|
558
|
-
R=prepare_capm_portfolio(tickerlist,sharelist,mktidx,start,end)
|
559
|
-
if R is None:
|
560
|
-
print(" #Error(capm_beta_portfolioyearly_excel): failed to prepare capm data")
|
561
|
-
print(" Information:",tickerlist,sharelist,mktidx,start,end)
|
562
|
-
return
|
563
|
-
|
564
|
-
#用于保存beta(CAPM)和beta
|
565
|
-
import pandas as pd
|
566
|
-
betas=pd.DataFrame(columns=('Year','Beta','intercept','R-sqr','p-value'))
|
567
|
-
|
568
|
-
#分年度OLS回归
|
569
|
-
from scipy import stats
|
570
|
-
for year in yearlist:
|
571
|
-
#print(year,' ',end='')
|
572
|
-
r=R[R['Year']==year]
|
573
|
-
if len(r)==0: continue
|
574
|
-
try:
|
575
|
-
output=stats.linregress(r['Close_x'],r['Close_y'])
|
576
|
-
except:
|
577
|
-
print(" #Error(capm_beta_portfolio_yearly_excel): no data available for regressing beta")
|
578
|
-
print(" Information:",year,R,r)
|
579
|
-
return
|
580
|
-
(beta,alpha,r_value,p_value,std_err)=output
|
581
|
-
|
582
|
-
row=pd.Series({'Year':year,'Beta':beta,'intercept':alpha, \
|
583
|
-
'R-sqr':r_value**2,'p-value':p_value})
|
584
|
-
try:
|
585
|
-
betas=betas.append(row,ignore_index=True)
|
586
|
-
except:
|
587
|
-
betas=betas._append(row,ignore_index=True)
|
588
|
-
|
589
|
-
betas2=betas.copy() #用于保存excel
|
590
|
-
betas2['Year']=betas2['Year'].astype('int')
|
591
|
-
betas2['Portfolio']=str(tickerlist)
|
592
|
-
betas2['Share Ratio']=str(sharelist)
|
593
|
-
betas2['Market Index']=mktidx
|
594
|
-
|
595
|
-
betas.set_index('Year',inplace=True) #用于绘图
|
596
|
-
|
597
|
-
#绘图:年度贝塔系数变化
|
598
|
-
df=pd.DataFrame(betas['Beta'])
|
599
|
-
title="Investment Portfolio's Annual CAPM Betas"+ \
|
600
|
-
"\nPortfolio: "+str(tickerlist)+"\nComposition: "+str(sharelist)
|
601
|
-
foot="\nSource: Sina Finance/Yahoo Finance"
|
602
|
-
plot_trend(title,foot,df,power=2)
|
603
|
-
|
604
|
-
"""
|
605
|
-
#为折线加数据标签
|
606
|
-
for a,b in zip(betas.index,betas['Beta']):
|
607
|
-
plt.text(a,b+0.02,str(round(b,2)),ha='center',va='bottom',fontsize=7)
|
608
|
-
plt.show()
|
609
|
-
"""
|
610
|
-
|
611
|
-
#保存到Excel
|
612
|
-
import pandas as pd
|
613
|
-
try:
|
614
|
-
file1=pd.ExcelFile(excelfile)
|
615
|
-
except:
|
616
|
-
#不存在excelfile文件,直接写入
|
617
|
-
betas2.to_excel(excelfile,sheet_name=sheetname, \
|
618
|
-
header=True,encoding='utf-8')
|
619
|
-
print("***Results saved in",excelfile,"@ sheet",sheetname)
|
620
|
-
return
|
621
|
-
else:
|
622
|
-
#已存在excelfile文件,先将所有已有内容读出
|
623
|
-
dict=pd.read_excel(file1, None)
|
624
|
-
file1.close()
|
625
|
-
|
626
|
-
#获得所有sheet名字
|
627
|
-
sheetlist=list(dict.keys())
|
628
|
-
|
629
|
-
#检查新的sheet名字是否已存在
|
630
|
-
try:
|
631
|
-
pos=sheetlist.index(sheetname)
|
632
|
-
except:
|
633
|
-
#不存在重复
|
634
|
-
dup=False
|
635
|
-
else:
|
636
|
-
#存在重复,合并内容
|
637
|
-
dup=True
|
638
|
-
#print(dict[sheetlist[pos]],betas2)
|
639
|
-
df1=dict[sheetlist[pos]][['Year','Beta','intercept','R-sqr','p-value','Portfolio','Share Ratio','Market Index']]
|
640
|
-
df=pd.concat([df1,betas2],axis=0,ignore_index=True)
|
641
|
-
dict[sheetlist[pos]]=df
|
642
|
-
|
643
|
-
#将原有内容写回excelfile
|
644
|
-
result=pd.ExcelWriter(excelfile)
|
645
|
-
for s in sheetlist:
|
646
|
-
df1=dict[s][['Year','Beta','intercept','R-sqr','p-value','Portfolio','Share Ratio','Market Index']]
|
647
|
-
df1.to_excel(result,s,header=True,index=True,encoding='utf-8')
|
648
|
-
#写入新内容
|
649
|
-
if not dup: #sheetname未重复
|
650
|
-
betas2.to_excel(result,sheetname,header=True,index=True,encoding='utf-8')
|
651
|
-
try:
|
652
|
-
result.save()
|
653
|
-
result.close()
|
654
|
-
except:
|
655
|
-
print(" #Error(capm_beta_portfolio_yearly_excel): writing file permission denied")
|
656
|
-
print(" Information:",excelfile)
|
657
|
-
return
|
658
|
-
print("***Results saved in",excelfile,"@ sheet",sheetname)
|
659
|
-
return betas
|
660
|
-
|
661
|
-
if __name__=='__main__':
|
662
|
-
yearlist=['2013','2014','2015','2016','2017','2018','2019']
|
663
|
-
excelfile='C:/temp/myexcel.xls'
|
664
|
-
capm_beta_portfolio_yearly_excel(['AAPL','MSFT'],[2,1],'^GSPC',yearlist, excelfile,'p01')
|
665
|
-
|
666
|
-
#==============================================================================
|
667
|
-
def compare2_betas_yearly(ticker1,ticker2,mktidx,yearlist):
|
668
|
-
"""
|
669
|
-
函数功能:分年度计算两只股票的CAPM模型贝塔系数,并绘图对比其风险特征的对冲性
|
670
|
-
输入参数:
|
671
|
-
ticker1: 股票代码
|
672
|
-
ticker2: 股票代码
|
673
|
-
mktidx: 指数代码
|
674
|
-
yearlist: 年度列表,start日期要给第一个年份留出至少一年数据供回归使用
|
675
|
-
输出数据:
|
676
|
-
按年份绘图贝塔系数的变化
|
677
|
-
无返回数据
|
678
|
-
"""
|
679
|
-
#仅用于测试,完成后应注释掉
|
680
|
-
#stkcd1='600028.SS'
|
681
|
-
#stkcd2='600036.SS'
|
682
|
-
#mktidx='000001.SS'
|
683
|
-
#yearlist=['2013','2014','2015','2016','2017','2018','2019']
|
684
|
-
|
685
|
-
|
686
|
-
#运行开始信息
|
687
|
-
print(" Comparing stock CAPM betas, please wait ...")
|
688
|
-
|
689
|
-
#生成开始结束日期
|
690
|
-
Y4=str(int(yearlist[0])-1)
|
691
|
-
start=Y4+'-01-01'
|
692
|
-
end=yearlist[-1]+'-12-31'
|
693
|
-
|
694
|
-
#读取股价并准备好收益率数据
|
695
|
-
R1=prepare_capm_data(ticker1,mktidx,start,end)
|
696
|
-
if R1 is None:
|
697
|
-
print(" #Error(compare2_betas_yearly): failed to prepare capm data")
|
698
|
-
print(" Information:",ticker1,mktidx,start,end)
|
699
|
-
return
|
700
|
-
|
701
|
-
R2=prepare_capm_data(ticker2,mktidx,start,end)
|
702
|
-
if R2 is None:
|
703
|
-
print(" #Error(compare2_betas_yearly): failed to prepare capm data")
|
704
|
-
print(" Information:",ticker2,mktidx,start,end)
|
705
|
-
return
|
706
|
-
|
707
|
-
#用于保存beta(CAPM)
|
708
|
-
import pandas as pd
|
709
|
-
betas1=pd.DataFrame(columns=('Year','Beta','alpha','R-sqr','p-value'))
|
710
|
-
#分年度OLS回归
|
711
|
-
from scipy import stats
|
712
|
-
for year in yearlist:
|
713
|
-
r=R1[R1['Year']==year]
|
714
|
-
if len(r)==0: continue
|
715
|
-
try:
|
716
|
-
output=stats.linregress(r['Close_x'],r['Close_y'])
|
717
|
-
except:
|
718
|
-
print(" #Error(compare2_betas_yearly): no data for regression")
|
719
|
-
print(" Information:",stkcd1,year,r,R1)
|
720
|
-
continue
|
721
|
-
(beta,alpha,r_value,p_value,std_err)=output
|
722
|
-
|
723
|
-
row=pd.Series({'Year':year,'Beta':beta,'alpha':alpha, \
|
724
|
-
'R-sqr':r_value**2,'p-value':p_value})
|
725
|
-
try:
|
726
|
-
betas1=betas1.append(row,ignore_index=True)
|
727
|
-
except:
|
728
|
-
betas1=betas1._append(row,ignore_index=True)
|
729
|
-
#print(" Calculated CAPM beta of",stkcd1,'on year',year)
|
730
|
-
|
731
|
-
betas1.set_index('Year',inplace=True)
|
732
|
-
|
733
|
-
betas2=pd.DataFrame(columns=('Year','Beta','alpha','R-sqr','p-value'))
|
734
|
-
for year in yearlist:
|
735
|
-
#print(year,' ',end='')
|
736
|
-
r=R2[R2['Year']==year]
|
737
|
-
if len(r)==0: continue
|
738
|
-
try:
|
739
|
-
output=stats.linregress(r['Close_x'],r['Close_y'])
|
740
|
-
except:
|
741
|
-
print(" #Error(compare2_betas_yearly): no data for regression")
|
742
|
-
print(" Information:",stkcd2,year,r,R2)
|
743
|
-
continue
|
744
|
-
(beta,alpha,r_value,p_value,std_err)=output
|
745
|
-
row=pd.Series({'Year':year,'Beta':beta,'alpha':alpha, \
|
746
|
-
'R-sqr':r_value**2,'p-value':p_value})
|
747
|
-
try:
|
748
|
-
betas2=betas2.append(row,ignore_index=True)
|
749
|
-
except:
|
750
|
-
betas2=betas2._append(row,ignore_index=True)
|
751
|
-
#print(" Calculated CAPM beta of",stkcd2,'on year',year)
|
752
|
-
|
753
|
-
betas2.set_index('Year',inplace=True)
|
754
|
-
|
755
|
-
#绘图:年度贝塔系数变化
|
756
|
-
plt.plot(betas1['Beta'],label=ticker_name(ticker1),c='red',marker='o',lw=1)
|
757
|
-
plt.plot(betas2['Beta'],label=ticker_name(ticker2),c='blue',marker='D',lw=2,linestyle='--')
|
758
|
-
|
759
|
-
#plt.axhline(y=1.0,color='b',linestyle=':',c='green',label='市场平均风险')
|
760
|
-
plt.axhline(y=1.0,color='b',linestyle=':',c='black')
|
761
|
-
|
762
|
-
plt.ylabel("贝塔系数",fontweight='bold')
|
763
|
-
plt.xticks(rotation=45,fontweight='bold')
|
764
|
-
trtitle="比较证券之间的贝塔系数"+"\n"+ticker_name(ticker1)+" vs "+ticker_name(ticker2)
|
765
|
-
plt.title(trtitle,fontweight='bold')
|
766
|
-
plt.legend(loc='best')
|
767
|
-
|
768
|
-
import datetime; today = datetime.date.today()
|
769
|
-
plt.xlabel("数据来源:新浪/stooq/fred,基于"+ticker_name(mktidx)+','+str(today))
|
770
|
-
|
771
|
-
plt.gca().set_facecolor('whitesmoke')
|
772
|
-
plt.show()
|
773
|
-
|
774
|
-
return betas1,betas2
|
775
|
-
|
776
|
-
if __name__=='__main__':
|
777
|
-
yearlist=['2013','2014','2015','2016','2017','2018','2019']
|
778
|
-
compare2_betas_yearly('AMZN','WMT','^GSPC',yearlist)
|
779
|
-
compare2_betas_yearly('601857.SS','600036.SS','000001.SS',yearlist)
|
780
|
-
|
781
|
-
#==============================================================================
|
782
|
-
#==============================================================================
|
783
|
-
#==============================================================================
|