siat 2.11.1__py3-none-any.whl → 2.11.2__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 +0 -0
- siat/security_trend.py +380 -306
- siat/transaction.py +198 -321
- siat/translate.py +1 -1
- {siat-2.11.1.dist-info → siat-2.11.2.dist-info}/METADATA +1 -1
- {siat-2.11.1.dist-info → siat-2.11.2.dist-info}/RECORD +9 -9
- {siat-2.11.1.dist-info → siat-2.11.2.dist-info}/WHEEL +0 -0
- {siat-2.11.1.dist-info → siat-2.11.2.dist-info}/top_level.txt +0 -0
siat/security_trend.py
CHANGED
@@ -1,352 +1,426 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
2
3
|
"""
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
创建日期:2023年7月15日
|
7
|
-
最新修订日期:2023年7月16日
|
8
|
-
作者:王德宏 (WANG Dehong, Peter)
|
9
|
-
作者单位:北京外国语大学国际商学院
|
10
|
-
作者邮件:wdehong2000@163.com
|
11
|
-
版权所有:王德宏
|
12
|
-
用途限制:仅限研究与教学使用!
|
13
|
-
特别声明:作者不对使用本工具进行证券投资导致的任何损益负责!
|
4
|
+
版权:王德宏,北京外国语大学国际商学院
|
5
|
+
功能:计算CAPM模型贝塔系数的调整值
|
6
|
+
版本:2.1,2019-7-25
|
14
7
|
"""
|
15
8
|
|
16
9
|
#==============================================================================
|
17
10
|
#关闭所有警告
|
18
11
|
import warnings; warnings.filterwarnings('ignore')
|
19
|
-
#==============================================================================
|
20
12
|
from siat.common import *
|
21
13
|
from siat.translate import *
|
22
|
-
from siat.stock import *
|
23
|
-
from siat.security_prices import *
|
24
|
-
from siat.risk_adjusted_return import *
|
25
|
-
from siat.valuation import *
|
26
14
|
from siat.grafix import *
|
27
|
-
|
28
|
-
import pandas as pd
|
29
|
-
import datetime as dt; today=str(dt.date.today())
|
15
|
+
from siat.security_prices import *
|
30
16
|
#==============================================================================
|
17
|
+
import matplotlib.pyplot as plt
|
18
|
+
|
19
|
+
#处理绘图汉字乱码问题
|
20
|
+
import sys; czxt=sys.platform
|
21
|
+
if czxt in ['win32','win64']:
|
22
|
+
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置默认字体
|
23
|
+
mpfrc={'font.family': 'SimHei'}
|
24
|
+
|
25
|
+
if czxt in ['darwin']: #MacOSX
|
26
|
+
plt.rcParams['font.family']= ['Heiti TC']
|
27
|
+
mpfrc={'font.family': 'Heiti TC'}
|
28
|
+
|
29
|
+
if czxt in ['linux']: #website Jupyter
|
30
|
+
plt.rcParams['font.family']= ['Heiti TC']
|
31
|
+
mpfrc={'font.family':'Heiti TC'}
|
32
|
+
|
33
|
+
# 解决保存图像时'-'显示为方块的问题
|
34
|
+
plt.rcParams['axes.unicode_minus'] = False
|
31
35
|
#==============================================================================
|
36
|
+
def prepare_capm(stkcd,mktidx,start,end):
|
37
|
+
"""
|
38
|
+
函数功能:准备计算一只股票CAPM模型贝塔系数的数据,并标记年度
|
39
|
+
输入参数:
|
40
|
+
stkcd: 股票代码
|
41
|
+
mktidx: 指数代码
|
42
|
+
start:使用股票价格数据的开始日期,MM/DD/YYYY
|
43
|
+
end:使用股票价格数据的结束日期,MM/DD/YYYY
|
44
|
+
输出数据:
|
45
|
+
返回数据:带年度标记的可直接用于capm回归的股票收益率数据
|
46
|
+
"""
|
47
|
+
|
48
|
+
#仅用于调试,正式使用前应注释掉
|
49
|
+
#stkcd='002504.SZ'; mktidx='000001.SS'
|
50
|
+
#start="12/31/2011"; end="12/31/2018"
|
51
|
+
|
52
|
+
#抓取股价和指数
|
53
|
+
stock=get_price(stkcd,start,end)
|
54
|
+
if stock is None:
|
55
|
+
print(" #Error(prepare_capm): no data retrieved from server!")
|
56
|
+
return None
|
57
|
+
market=get_price(mktidx,start,end)
|
58
|
+
if market is None:
|
59
|
+
print(" #Error(prepare_capm): no index data retrieved from server!")
|
60
|
+
return None
|
61
|
+
|
62
|
+
#计算日收益率
|
63
|
+
import pandas as pd
|
64
|
+
stkret=pd.DataFrame(stock['Close'].pct_change())
|
65
|
+
mktret=pd.DataFrame(market['Close'].pct_change())
|
66
|
+
|
67
|
+
#合并,去掉空缺
|
68
|
+
R=pd.merge(mktret,stkret,how='left',left_index=True,right_index=True)
|
69
|
+
R=R.dropna()
|
70
|
+
|
71
|
+
#标记各个年度
|
72
|
+
R['Year']=R.index.strftime("%Y")
|
73
|
+
|
74
|
+
#返回带年份的股票收益率序列
|
75
|
+
return R
|
76
|
+
|
32
77
|
if __name__=='__main__':
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
twinx=True
|
54
|
-
loc1='upper left'
|
55
|
-
loc2='lower right'
|
56
|
-
source='auto'
|
57
|
-
|
58
|
-
#测试组3
|
59
|
-
ticker='AAPL'
|
60
|
-
indicator=['Close','Open','High','Low']
|
61
|
-
start='default'
|
62
|
-
end='default'
|
63
|
-
datatag=False
|
64
|
-
power=0
|
65
|
-
graph=True
|
66
|
-
twinx=True
|
67
|
-
loc1='upper left'
|
68
|
-
loc2='lower right'
|
69
|
-
source='auto'
|
78
|
+
R1=prepare_capm('0700.HK','^HSI','2014-01-01','2018-12-31')
|
79
|
+
|
80
|
+
#==============================================================================
|
81
|
+
#==============================================================================
|
82
|
+
def get_beta_ML(stkcd,mktidx,yearlist,printout=True,graph=True):
|
83
|
+
"""
|
84
|
+
函数功能:使用ML方法调整一只股票的CAPM模型贝塔系数
|
85
|
+
输入参数:
|
86
|
+
stkcd: 股票代码
|
87
|
+
mktidx: 指数代码
|
88
|
+
yearlist:年度列表,列出其中期间的贝塔系数
|
89
|
+
输出数据:
|
90
|
+
显示CAPM市场模型回归的beta, 以及ML调整后的beta系数
|
91
|
+
返回数据:年度CAPM贝塔系数和ML调整后的beta系数
|
92
|
+
"""
|
93
|
+
|
94
|
+
#仅为测试用,完成后应立即注释掉
|
95
|
+
#stkcd='0700.HK'
|
96
|
+
#mktidx='^HSI'
|
97
|
+
#yearlist=['2015','2016','2017','2018']
|
70
98
|
|
71
|
-
|
99
|
+
Y4=str(int(yearlist[0])-1)
|
100
|
+
start=Y4+'-01-01'
|
101
|
+
end=yearlist[-1]+'-12-31'
|
102
|
+
|
103
|
+
#读取股价并准备好收益率数据
|
104
|
+
try:
|
105
|
+
R=prepare_capm(stkcd,mktidx,start,end)
|
106
|
+
except:
|
107
|
+
print(" #Error(get_beta_ML): Preparing CAPM data failed!")
|
108
|
+
return None
|
109
|
+
|
110
|
+
if (R is None):
|
111
|
+
print(" #Error(get_beta_ML): server time out")
|
112
|
+
return None
|
113
|
+
if (len(R) == 0):
|
114
|
+
print(" #Error(get_beta_ML): server returned empty data")
|
115
|
+
return None
|
72
116
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
117
|
+
#用于保存beta(CAPM)和beta(ML)
|
118
|
+
import pandas as pd
|
119
|
+
betas=pd.DataFrame(columns=('Year','Beta(CAPM)','Beta(ML)'))
|
120
|
+
|
121
|
+
#计算Merrill-Lynch方法贝塔系数调整
|
122
|
+
from scipy import stats
|
123
|
+
for year in yearlist:
|
124
|
+
r=R[R['Year']==year]
|
125
|
+
if len(r) != 0:
|
126
|
+
output=stats.linregress(r['Close_x'],r['Close_y'])
|
127
|
+
(beta,alpha,r_value,p_value,std_err)=output
|
128
|
+
beta_ML=beta*2.0/3.0+1.0/3.0
|
129
|
+
#整齐输出
|
130
|
+
#print(year,"%6.4f "%(beta),"%6.4f "%(beta_ML))
|
131
|
+
|
132
|
+
row=pd.Series({'Year':year,'Beta(CAPM)':beta,'Beta(ML)':beta_ML})
|
133
|
+
try:
|
134
|
+
betas=betas.append(row,ignore_index=True)
|
135
|
+
except:
|
136
|
+
betas=betas._append(row,ignore_index=True)
|
137
|
+
|
138
|
+
betas.set_index(["Year"], inplace=True)
|
78
139
|
|
140
|
+
if printout == True: printdf_betas(betas,2)
|
141
|
+
if graph == True:
|
142
|
+
model="贝塔系数的简单调整法"
|
143
|
+
draw2_betas(model,mktidx,stkcd,betas)
|
144
|
+
|
145
|
+
return betas
|
146
|
+
|
147
|
+
#==============================================================================
|
148
|
+
def printdf_betas(df,decimal=2):
|
149
|
+
"""
|
150
|
+
功能:整齐地显示数据框的内容,自动调整各列宽度
|
151
|
+
"""
|
152
|
+
#打印时保留的小数点位数
|
153
|
+
dec="%."+str(decimal)+"f"
|
154
|
+
format=lambda x: dec % x
|
155
|
+
df1=df.applymap(format)
|
79
156
|
|
157
|
+
import pandas as pd
|
158
|
+
#调整最佳列宽
|
159
|
+
old_width = pd.get_option('display.max_colwidth')
|
160
|
+
pd.set_option('display.max_colwidth', -1)
|
161
|
+
print(df1)
|
162
|
+
pd.set_option('display.max_colwidth', old_width)
|
163
|
+
|
164
|
+
return
|
80
165
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
datatag=False,power=0, \
|
89
|
-
smooth=True,date_range=False,date_freq=False,annotate=False, \
|
90
|
-
preprocess='none',scaling_option='start', \
|
91
|
-
printout=False, \
|
92
|
-
source='auto'):
|
166
|
+
if __name__=='__main__':
|
167
|
+
yearlist=gen_yearlist['2010','2019']
|
168
|
+
betas=get_beta_ML('AAPL','^GSPC',yearlist)
|
169
|
+
betas2=get_beta_ML('BILI','^GSPC',yearlist)
|
170
|
+
betas3=get_beta_ML('0700.HK','^HSI',yearlist)
|
171
|
+
yearlist1=['2015','2016','2017','2018']
|
172
|
+
betas3=get_beta_ML('0700.HK','^HSI',yearlist1)
|
93
173
|
|
174
|
+
#==============================================================================
|
175
|
+
def draw2_betas(model,scope,ticker,betas):
|
176
|
+
"""
|
177
|
+
功能:绘制双曲线的贝塔因子变化图
|
178
|
+
输入参数:
|
179
|
+
model: 模型类型, 任意字符串(例如Merrill-Lynch Beta Adjustment)
|
180
|
+
scope: 市场指数, 任意字符串(例如Standard & Poor 500)
|
181
|
+
ticker:股票代码
|
182
|
+
输出:图形
|
183
|
+
"""
|
184
|
+
#仅用作测试,完成后应注释掉
|
185
|
+
#model="Merrill-Lynch Beta Adjustment"
|
186
|
+
#scope="Standard & Poor 500"
|
187
|
+
#ticker="AAPL"
|
188
|
+
|
189
|
+
#取得股票和指数名字,对于非美股可能耗时较长
|
190
|
+
"""
|
191
|
+
import yfinance as yf
|
192
|
+
mktidx= yf.Ticker(scope)
|
193
|
+
idxinfo=mktidx.info
|
194
|
+
idxname=idxinfo['shortName']
|
195
|
+
stkcd=yf.Ticker(ticker)
|
196
|
+
stkinfo=stkcd.info
|
197
|
+
stkname=stkinfo['shortName']
|
198
|
+
title1="\n"+stkname+"\n"+model+"\n(Benchmark on "+idxname+")"
|
199
|
+
"""
|
200
|
+
title1=codetranslate(ticker)+": "+model+"\n(基于"+codetranslate(scope)+")"
|
201
|
+
|
202
|
+
#转换索引类型为DatetimeIndex,便于后续处理
|
94
203
|
"""
|
95
|
-
|
204
|
+
import pandas as pd
|
205
|
+
betas['Date']=betas.index
|
206
|
+
betas['Date']=pd.to_datetime(betas['Date'])
|
207
|
+
betas.set_index('Date',inplace=True)
|
208
|
+
"""
|
209
|
+
|
210
|
+
#获得列明
|
211
|
+
betalist=betas.columns.values.tolist()
|
212
|
+
beta1=betalist[0]
|
213
|
+
beta2=betalist[1]
|
214
|
+
|
215
|
+
try:
|
216
|
+
plt.plot(betas[beta1],label=beta1,marker='o',color='red')
|
217
|
+
plt.plot(betas[beta2],label=beta2,marker='*',linewidth=2,ls='-.',color='blue')
|
218
|
+
except:
|
219
|
+
print(" #Error(draw2_betas): no available data for drawing!")
|
220
|
+
return
|
221
|
+
plt.axhline(y=1.0,color='b',linestyle=':',label='市场线')
|
222
|
+
plt.title(title1,fontsize=12,fontweight='bold')
|
223
|
+
plt.ylabel("贝塔系数",fontsize=12,fontweight='bold')
|
96
224
|
|
97
|
-
|
225
|
+
plt.gcf().autofmt_xdate() # 优化标注(自动倾斜)
|
226
|
+
#plt.xticks(rotation=30)
|
227
|
+
plt.legend(loc='best')
|
98
228
|
|
99
|
-
|
100
|
-
|
101
|
-
ticker_num=1
|
102
|
-
tickers=[ticker]
|
103
|
-
elif isinstance(ticker,list):
|
104
|
-
ticker_num=len(ticker)
|
105
|
-
tickers=ticker
|
106
|
-
else:
|
107
|
-
print(" #Error(security_trend): unrecognizable security codes",ticker)
|
108
|
-
return None
|
229
|
+
import datetime; today = datetime.date.today()
|
230
|
+
plt.xlabel("数据来源:新浪,"+str(today))
|
109
231
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
if end in ['default','today']:
|
114
|
-
todate=today
|
115
|
-
else:
|
116
|
-
validdate,todate=check_date2(end)
|
117
|
-
if not validdate:
|
118
|
-
print(" #Warning(security_trend): invalid date for",end)
|
119
|
-
todate=today
|
120
|
-
|
121
|
-
# 检查日期:开始日期
|
122
|
-
start=start.lower()
|
123
|
-
if start in ['default','mrm','l1m']: # 默认近一个月
|
124
|
-
fromdate=date_adjust(todate,adjust=-31)
|
125
|
-
elif start in ['mrq','l3m']: # 近三个月
|
126
|
-
fromdate=date_adjust(todate,adjust=-31*3)
|
127
|
-
elif start in ['l6m']: # 近6个月
|
128
|
-
fromdate=date_adjust(todate,adjust=-31*6)
|
129
|
-
elif start in ['mry','l12m']: # 近一年
|
130
|
-
fromdate=date_adjust(todate,adjust=-366)
|
131
|
-
elif start in ['lty','l3y']: # 近三年以来
|
132
|
-
fromdate=date_adjust(todate,adjust=-366*3)
|
133
|
-
elif start in ['lfy','l5y']: # 近五年以来
|
134
|
-
fromdate=date_adjust(todate,adjust=-366*5)
|
135
|
-
elif start in ['l10y']: # 近十年以来
|
136
|
-
fromdate=date_adjust(todate,adjust=-366*10)
|
137
|
-
elif start in ['ytd']: # 今年以来
|
138
|
-
fromdate=str(today.year)+'-1-1'
|
139
|
-
else:
|
140
|
-
validdate,fromdate=check_date2(start)
|
141
|
-
if not validdate:
|
142
|
-
print(" #Warning(security_trend): invalid date for",start,"/b, set to MRM")
|
143
|
-
fromdate=date_adjust(todate,adjust=-31)
|
144
|
-
|
145
|
-
# 处理K线图
|
146
|
-
if kline and not kline_demo:
|
147
|
-
# 跟踪
|
148
|
-
#print(tickers[0],fromdate,todate)
|
149
|
-
if start in ['default']:
|
150
|
-
fromdate=date_adjust(todate,adjust=-60)
|
151
|
-
if not isinstance(mav,list):
|
152
|
-
mav=[mav]
|
153
|
-
df=candlestick(stkcd=tickers[0],fromdate=fromdate,todate=todate,mav=mav)
|
154
|
-
return df
|
155
|
-
|
156
|
-
if kline and kline_demo:
|
157
|
-
if start in ['default']:
|
158
|
-
fromdate=date_adjust(todate,adjust=-7)
|
159
|
-
|
160
|
-
df=candlestick_demo(tickers[0],fromdate=fromdate,todate=todate)
|
161
|
-
return df
|
232
|
+
plt.show()
|
233
|
+
|
234
|
+
return
|
162
235
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
df=stock_dividend(ticker=tickers[0],fromdate=fromdate,todate=todate)
|
169
|
-
return df
|
236
|
+
if __name__=='__main__':
|
237
|
+
model="ML Beta Adjustment"
|
238
|
+
scope="SP500"
|
239
|
+
ticker="AAPL"
|
240
|
+
draw2_betas(model,scope,ticker,betas)
|
170
241
|
|
171
|
-
if stock_split:
|
172
|
-
if start in ['default']:
|
173
|
-
fromdate=date_adjust(todate,adjust=-365*5)
|
174
|
-
|
175
|
-
df=stock_split(ticker=tickers[0],fromdate=fromdate,todate=todate)
|
176
|
-
return df
|
177
|
-
|
178
242
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
'Monthly Adj Ret','Monthly Adj Ret%','Quarterly Ret','Quarterly Ret%',
|
196
|
-
'Quarterly Adj Ret','Quarterly Adj Ret%','Annual Ret','Annual Ret%',
|
197
|
-
'Annual Adj Ret','Annual Adj Ret%','Exp Ret','Exp Ret%','Exp Adj Ret',
|
198
|
-
'Exp Adj Ret%','Weekly Price Volatility','Weekly Adj Price Volatility',
|
199
|
-
'Monthly Price Volatility','Monthly Adj Price Volatility',
|
200
|
-
'Quarterly Price Volatility','Quarterly Adj Price Volatility',
|
201
|
-
'Annual Price Volatility','Annual Adj Price Volatility',
|
202
|
-
'Exp Price Volatility','Exp Adj Price Volatility',
|
203
|
-
'Weekly Ret Volatility','Weekly Ret Volatility%',
|
204
|
-
'Weekly Adj Ret Volatility','Weekly Adj Ret Volatility%',
|
205
|
-
'Monthly Ret Volatility', 'Monthly Ret Volatility%',
|
206
|
-
'Monthly Adj Ret Volatility', 'Monthly Adj Ret Volatility%',
|
207
|
-
'Quarterly Ret Volatility', 'Quarterly Ret Volatility%',
|
208
|
-
'Quarterly Adj Ret Volatility', 'Quarterly Adj Ret Volatility%',
|
209
|
-
'Annual Ret Volatility', 'Annual Ret Volatility%',
|
210
|
-
'Annual Adj Ret Volatility', 'Annual Adj Ret Volatility%',
|
211
|
-
'Exp Ret Volatility', 'Exp Ret Volatility%', 'Exp Adj Ret Volatility',
|
212
|
-
'Exp Adj Ret Volatility%', 'Weekly Ret LPSD', 'Weekly Ret LPSD%',
|
213
|
-
'Weekly Adj Ret LPSD', 'Weekly Adj Ret LPSD%', 'Monthly Ret LPSD',
|
214
|
-
'Monthly Ret LPSD%', 'Monthly Adj Ret LPSD', 'Monthly Adj Ret LPSD%',
|
215
|
-
'Quarterly Ret LPSD', 'Quarterly Ret LPSD%', 'Quarterly Adj Ret LPSD',
|
216
|
-
'Quarterly Adj Ret LPSD%', 'Annual Ret LPSD', 'Annual Ret LPSD%',
|
217
|
-
'Annual Adj Ret LPSD', 'Annual Adj Ret LPSD%', 'Exp Ret LPSD',
|
218
|
-
'Exp Ret LPSD%', 'Exp Adj Ret LPSD', 'Exp Adj Ret LPSD%',
|
219
|
-
]
|
220
|
-
|
221
|
-
indicator_list2=['treynor','sharpe','sortino','alpha','Treynor','Sharpe','Sortino','Alpha']
|
222
|
-
indicator_list3=['pe','pb','mv','PE','PB','MV','Pe','Pb','Mv']
|
243
|
+
#==============================================================================
|
244
|
+
def get_beta_SW(stkcd,mktidx,yearlist,printout=True,graph=True):
|
245
|
+
"""
|
246
|
+
函数功能:使用SW方法调整一只股票的CAPM模型贝塔系数
|
247
|
+
输入参数:
|
248
|
+
stkcd: 股票代码
|
249
|
+
mktidx: 指数代码
|
250
|
+
yearlist:年度列表,列出其中期间的贝塔系数
|
251
|
+
输出数据:显示CAPM市场模型回归的beta, 以及调整后的beta系数
|
252
|
+
返回数据:CAPM市场模型回归的beta, 以及调整后的beta系数
|
253
|
+
"""
|
254
|
+
|
255
|
+
#仅为测试用,完成后应立即注释掉
|
256
|
+
#stkcd='0700.HK'
|
257
|
+
#mktidx='^HSI'
|
258
|
+
#yearlist=['2015','2016','2017','2018']
|
223
259
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
print(" Supported indicators:")
|
229
|
-
printlist(indicator_list1,numperline=4,beforehand=' ',separator=' ')
|
230
|
-
printlist(indicator_list2,numperline=5,beforehand=' ',separator=' ')
|
231
|
-
printlist(indicator_list3,numperline=5,beforehand=' ',separator=' ')
|
232
|
-
return None
|
260
|
+
#生成开始结束日期
|
261
|
+
Y4=str(int(yearlist[0])-1)
|
262
|
+
start=Y4+'-01-01'
|
263
|
+
end=yearlist[-1]+'-12-31'
|
233
264
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
list_group1=list_group2=list_group3=0
|
240
|
-
for m in measures:
|
241
|
-
if m in indicator_list3:
|
242
|
-
list_group3=1
|
243
|
-
indicator_group3=True
|
244
|
-
if m in indicator_list2:
|
245
|
-
list_group2=1
|
246
|
-
indicator_group2=True
|
247
|
-
if m in indicator_list1:
|
248
|
-
list_group1=1
|
249
|
-
indicator_group1=True
|
250
|
-
|
251
|
-
if list_group1+list_group2+list_group3 >= 2:
|
252
|
-
print(" #Error(security_trend): cannot support in different indicator groups together for",measures)
|
265
|
+
#读取股价并准备好收益率数据
|
266
|
+
try:
|
267
|
+
R=prepare_capm(stkcd,mktidx,start,end)
|
268
|
+
except:
|
269
|
+
print(" #Error(get_beta_SW): preparing CAPM data failed!")
|
253
270
|
return None
|
271
|
+
|
272
|
+
if (R is None):
|
273
|
+
print(" #Error(get_beta_SW): server time out")
|
274
|
+
return None
|
275
|
+
if (len(R) == 0):
|
276
|
+
print(" #Error(get_beta_SW): server returned empty data")
|
277
|
+
return None
|
278
|
+
|
279
|
+
#用于保存beta(CAPM)和beta(SW)
|
280
|
+
import pandas as pd
|
281
|
+
betas=pd.DataFrame(columns=('Year','Beta(CAPM)','Beta(SW)'))
|
282
|
+
|
283
|
+
#计算Scholes-William调整
|
284
|
+
R['Close_x+1']=R['Close_x'].shift(1)
|
285
|
+
R['Close_x-1']=R['Close_x'].shift(-1)
|
286
|
+
R=R.dropna() #stats.linregress不接受空缺值
|
287
|
+
|
288
|
+
from scipy import stats
|
289
|
+
for year in yearlist:
|
290
|
+
r=R[R['Year']==year]
|
291
|
+
if len(r) != 0:
|
292
|
+
output=stats.linregress(r['Close_x'],r['Close_y'])
|
293
|
+
(beta0,alpha,r_value,p_value,std_err)=output
|
294
|
+
|
295
|
+
output=stats.linregress(r['Close_x+1'],r['Close_y'])
|
296
|
+
(beta1,alpha,r_value,p_value,std_err)=output
|
297
|
+
|
298
|
+
output=stats.linregress(r['Close_x-1'],r['Close_y'])
|
299
|
+
(beta_1,alpha,r_value,p_value,std_err)=output
|
300
|
+
|
301
|
+
output=stats.linregress(r['Close_x-1'],r['Close_x'])
|
302
|
+
(rou,alpha,r_value,p_value,std_err)=output
|
303
|
+
|
304
|
+
beta_SW=(beta_1+beta0+beta1)/(1.0+2.0*rou)
|
305
|
+
row=pd.Series({'Year':year,'Beta(CAPM)':beta0,'Beta(SW)':beta_SW})
|
306
|
+
try:
|
307
|
+
betas=betas.append(row,ignore_index=True)
|
308
|
+
except:
|
309
|
+
betas=betas._append(row,ignore_index=True)
|
254
310
|
|
255
|
-
|
256
|
-
if ticker_num==1 and indicator_num==1 and indicator_group1:
|
257
|
-
df=security_indicator(ticker=tickers[0],indicator=measures[0], \
|
258
|
-
fromdate=fromdate,todate=todate, \
|
259
|
-
datatag=datatag,power=power,graph=graph, \
|
260
|
-
source=source)
|
261
|
-
return df
|
262
|
-
|
263
|
-
# 情形2:单个证券,两个普通指标,twinx==True
|
264
|
-
if ticker_num==1 and indicator_num == 2 and indicator_group1 and twinx:
|
265
|
-
df=compare_security(tickers=tickers[0],measures=measures[:2], \
|
266
|
-
fromdate=fromdate,todate=todate,twinx=twinx, \
|
267
|
-
loc1=loc1,loc2=loc2,graph=graph,source=source)
|
268
|
-
return df
|
311
|
+
betas.set_index(["Year"], inplace=True)
|
269
312
|
|
270
|
-
|
271
|
-
if
|
272
|
-
|
273
|
-
|
274
|
-
graph=graph,smooth=smooth,loc=loc1, \
|
275
|
-
date_range=date_range,date_freq=date_freq, \
|
276
|
-
annotate=annotate, \
|
277
|
-
source=source)
|
278
|
-
return df
|
313
|
+
if printout == True: printdf_betas(betas,2)
|
314
|
+
if graph == True:
|
315
|
+
model="贝塔系数的Scholes-Williams调整法"
|
316
|
+
draw2_betas(model,mktidx,stkcd,betas)
|
279
317
|
|
280
|
-
|
281
|
-
|
282
|
-
df=compare_security(tickers=tickers,measures=measures[0], \
|
283
|
-
fromdate=fromdate,todate=todate,twinx=twinx, \
|
284
|
-
loc1=loc1,loc2=loc2,graph=graph,source=source)
|
285
|
-
return df
|
286
|
-
|
287
|
-
# 情形5:两个及以上证券,取第一个普通指标
|
288
|
-
if ticker_num==2:
|
289
|
-
linewidth=2.5
|
290
|
-
elif ticker_num==3:
|
291
|
-
linewidth=2.0
|
292
|
-
else:
|
293
|
-
linewidth=1.5
|
294
|
-
|
295
|
-
if ((ticker_num == 2 and not twinx) or ticker_num > 2) and indicator_group1:
|
296
|
-
df=compare_msecurity(tickers=tickers,measure=measures[0], \
|
297
|
-
start=fromdate,end=todate, \
|
298
|
-
axhline_value=0,axhline_label='', \
|
299
|
-
preprocess=preprocess,linewidth=linewidth, \
|
300
|
-
scaling_option=scaling_option, \
|
301
|
-
graph=graph,loc=loc1, \
|
302
|
-
annotate=annotate,smooth=smooth, \
|
303
|
-
source=source)
|
304
|
-
return df
|
305
|
-
|
306
|
-
# 情形6:单个证券,单个或多个RAR指标
|
307
|
-
# 特别注意:与收益率对比时若使用扩展收益率可能导致矛盾,要使用滚动收益率
|
308
|
-
if indicator_group2 and ticker_num==1 and indicator_num >= 1:
|
309
|
-
df=compare_1security_mrar(ticker=tickers[0],rar_names=measures, \
|
310
|
-
start=fromdate,end=todate, \
|
311
|
-
market=market,market_index=market_index,RF=RF,window=window, \
|
312
|
-
axhline_value=0,axhline_label='零线',graph=graph,printout=printout, \
|
313
|
-
sortby=sortby,source=source,trailing=trailing,trend_threshhold=trend_threshhold, \
|
314
|
-
annotate=annotate)
|
315
|
-
return df
|
316
|
-
|
317
|
-
# 情形7:多个证券,取第一个RAR指标
|
318
|
-
# 特别注意:与收益率对比时若使用扩展收益率可能导致矛盾,要使用滚动收益率
|
319
|
-
if indicator_group2 and ticker_num > 1:
|
320
|
-
df=compare_mrar(tickers=tickers,rar_name=measures[0], \
|
321
|
-
start=fromdate,end=todate, \
|
322
|
-
market=market,market_index=market_index,RF=RF,window=window, \
|
323
|
-
axhline_value=0,axhline_label='零线',graph=graph,printout=printout, \
|
324
|
-
sortby=sortby,source=source,trailing=trailing,trend_threshhold=trend_threshhold, \
|
325
|
-
annotate=annotate)
|
326
|
-
return df
|
318
|
+
return betas
|
319
|
+
|
327
320
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
twinx=twinx,loc1=loc1,loc2=loc2, \
|
332
|
-
graph=graph,annotate=annotate)
|
333
|
-
return df
|
321
|
+
if __name__=='__main__':
|
322
|
+
yearlist=gen_yearlist('2010','2019')
|
323
|
+
betas_AAPL=get_beta_SW('AAPL','^GSPC',yearlist)
|
334
324
|
|
335
|
-
|
336
|
-
|
337
|
-
|
325
|
+
model="SW Beta Adjustment"
|
326
|
+
scope="SP500"
|
327
|
+
ticker="AAPL"
|
328
|
+
draw2_betas(model,scope,ticker,betas_AAPL)
|
338
329
|
|
339
330
|
#==============================================================================
|
340
|
-
|
341
|
-
|
331
|
+
def get_beta_dimson(stkcd,mktidx,yearlist,printout=True,graph=True):
|
332
|
+
"""
|
333
|
+
函数功能:使用Dimson(1979)方法调整一只股票的CAPM模型贝塔系数
|
334
|
+
输入参数:
|
335
|
+
stkcd: 股票代码
|
336
|
+
mktidx: 指数代码
|
337
|
+
yearlist:年度列表,用于计算年度贝塔系数
|
338
|
+
输出数据:显示CAPM市场模型回归的beta, 以及调整后的beta系数
|
339
|
+
返回数据:CAPM的beta, 以及调整后的beta系数
|
340
|
+
"""
|
342
341
|
|
342
|
+
#仅为测试用,完成后应立即注释掉
|
343
|
+
#stkcd='0700.HK'
|
344
|
+
#mktidx='^HSI'
|
345
|
+
#yearlist=['2015','2016','2017','2018']
|
346
|
+
|
347
|
+
#生成开始结束日期
|
348
|
+
Y4=str(int(yearlist[0])-1)
|
349
|
+
start=Y4+'-01-01'
|
350
|
+
end=yearlist[-1]+'-12-31'
|
351
|
+
|
352
|
+
#读取股价并准备好收益率数据
|
353
|
+
try:
|
354
|
+
R=prepare_capm(stkcd,mktidx,start,end)
|
355
|
+
except:
|
356
|
+
print(" #Error(get_beta_dimson): preparing CAPM data failed!")
|
357
|
+
return None
|
358
|
+
|
359
|
+
if (R is None):
|
360
|
+
print(" #Error(get_beta_dimson): server did not respond")
|
361
|
+
return None
|
362
|
+
if (len(R) == 0):
|
363
|
+
print(" #Error(get_beta_dimson): server returned empty data")
|
364
|
+
return None
|
343
365
|
|
366
|
+
#用于保存beta(CAPM)和beta(Dimson)
|
367
|
+
import pandas as pd
|
368
|
+
betas=pd.DataFrame(columns=('Year','Beta(CAPM)','Beta(Dimson)'))
|
344
369
|
|
370
|
+
#计算Dimson(1979)调整
|
371
|
+
R['Close_x+1']=R['Close_x'].shift(1)
|
372
|
+
R['Close_x-1']=R['Close_x'].shift(-1)
|
373
|
+
R=R.dropna()
|
345
374
|
|
375
|
+
from scipy import stats
|
376
|
+
import statsmodels.api as sm
|
377
|
+
for year in yearlist:
|
378
|
+
r=R[R['Year']==year]
|
379
|
+
if len(r) != 0:
|
380
|
+
output=stats.linregress(r['Close_x'],r['Close_y'])
|
381
|
+
(beta_capm,alpha,r_value,p_value,std_err)=output
|
382
|
+
|
383
|
+
#三个解释变量
|
384
|
+
RX=r[['Close_x-1','Close_x','Close_x+1']]
|
385
|
+
X1=sm.add_constant(RX) #要求回归具有截距项
|
386
|
+
Y=r['Close_y']
|
387
|
+
model = sm.OLS(Y,X1) #定义回归模型,X1为多元矩阵
|
388
|
+
results = model.fit() #进行OLS回归
|
346
389
|
|
390
|
+
(alpha,beta_1,beta0,beta1)=results.params #提取回归系数
|
391
|
+
beta_dimson=beta_1+beta0+beta1
|
347
392
|
|
393
|
+
row=pd.Series({'Year':year,'Beta(CAPM)':beta_capm, \
|
394
|
+
'Beta(Dimson)':beta_dimson})
|
395
|
+
try:
|
396
|
+
betas=betas.append(row,ignore_index=True)
|
397
|
+
except:
|
398
|
+
betas=betas._append(row,ignore_index=True)
|
348
399
|
|
400
|
+
betas.set_index(["Year"], inplace=True)
|
349
401
|
|
402
|
+
if printout == True: printdf_betas(betas,2)
|
403
|
+
if graph == True:
|
404
|
+
model="贝塔系数的Dimson调整法"
|
405
|
+
draw2_betas(model,mktidx,stkcd,betas)
|
350
406
|
|
407
|
+
return betas
|
408
|
+
|
409
|
+
if __name__=='__main__':
|
410
|
+
yearlist=gen_yearlist('2010','2019')
|
411
|
+
betas_MSFT=get_beta_dimson('MSFT','^GSPC',yearlist)
|
412
|
+
|
413
|
+
model="Dimson Beta Adjustment"
|
414
|
+
scope="SP500"
|
415
|
+
ticker="MSFT"
|
416
|
+
draw2_betas(model,scope,ticker,betas_MSFT)
|
351
417
|
|
418
|
+
betas_MSFT2=get_beta_dimson('MSFT','^DJI',yearlist)
|
419
|
+
|
420
|
+
model="Dimson Beta Adjustment"
|
421
|
+
scope="DJIA"
|
422
|
+
ticker="MSFT"
|
423
|
+
draw2_betas(model,scope,ticker,betas_MSFT2)
|
352
424
|
|
425
|
+
#==============================================================================
|
426
|
+
#============
|