siat 3.10.75__py3-none-any.whl → 3.10.125__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/assets_liquidity.py +168 -30
- siat/bond.py +34 -7
- siat/capm_beta.py +34 -9
- siat/common.py +88 -7
- siat/economy2.py +75 -1
- siat/exchange_bond_china.pickle +0 -0
- siat/fama_french.py +201 -12
- siat/financial_statements.py +26 -85
- siat/financials.py +114 -14
- siat/financials_china.py +1 -1
- siat/fund_china.py +6 -5
- siat/future_china.py +8 -2
- siat/holding_risk.py +38 -31
- siat/market_china.py +20 -10
- siat/markowitz2.py +72 -10
- siat/option_china.py +45 -17
- siat/option_pricing.py +3 -0
- siat/other_indexes.py +16 -3
- siat/risk_adjusted_return.py +182 -114
- siat/risk_evaluation.py +252 -20
- siat/sector_china.py +12 -9
- siat/security_price2.py +19 -4
- siat/security_prices.py +222 -23
- siat/security_trend2.py +3 -3
- siat/stock.py +32 -0
- siat/translate.py +18 -9
- siat/var_model_validation.py +59 -0
- {siat-3.10.75.dist-info → siat-3.10.125.dist-info}/METADATA +1 -1
- {siat-3.10.75.dist-info → siat-3.10.125.dist-info}/RECORD +32 -32
- {siat-3.10.75.dist-info → siat-3.10.125.dist-info}/LICENSE +0 -0
- {siat-3.10.75.dist-info → siat-3.10.125.dist-info}/WHEEL +0 -0
- {siat-3.10.75.dist-info → siat-3.10.125.dist-info}/top_level.txt +0 -0
siat/risk_adjusted_return.py
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
所属工具包:证券投资分析工具SIAT
|
5
5
|
SIAT:Security Investment Analysis Tool
|
6
6
|
创建日期:2018年10月16日
|
7
|
-
最新修订日期:
|
7
|
+
最新修订日期:2025年6月20日
|
8
8
|
作者:王德宏 (WANG Dehong, Peter)
|
9
9
|
作者单位:北京外国语大学国际商学院
|
10
10
|
作者邮件:wdehong2000@163.com
|
@@ -65,8 +65,9 @@ def calc_treynor_ratio(regdf):
|
|
65
65
|
#计算特雷诺指数
|
66
66
|
tr=ret_rf_mean/beta
|
67
67
|
|
68
|
-
ret_mean=regdf['
|
69
|
-
|
68
|
+
#ret_mean=regdf['Ret%'].mean()
|
69
|
+
rp_mean=ret_rf_mean
|
70
|
+
return tr,rp_mean,beta
|
70
71
|
|
71
72
|
#==============================================================================
|
72
73
|
def calc_alpha_ratio(regdf):
|
@@ -75,17 +76,15 @@ def calc_alpha_ratio(regdf):
|
|
75
76
|
输入:数据框,至少含有Ret-Rf和Mkt-Rf两项
|
76
77
|
输出:詹森阿尔法指数,Ret-Rf均值
|
77
78
|
"""
|
78
|
-
"""
|
79
79
|
#计算风险溢价Ret-RF均值
|
80
80
|
ret_rf_mean=regdf['Ret-RF'].mean()
|
81
|
-
"""
|
82
81
|
#使用CAPM回归计算投资组合的贝塔系数,这里得到的alpha就是Jensen's alpha
|
83
82
|
from scipy import stats
|
84
83
|
output=stats.linregress(regdf['Mkt-RF'],regdf['Ret-RF'])
|
85
84
|
(beta,alpha,r_value,p_value,std_err)=output
|
86
85
|
|
87
|
-
|
88
|
-
return alpha,
|
86
|
+
rp_mean=ret_rf_mean
|
87
|
+
return alpha,rp_mean,beta
|
89
88
|
|
90
89
|
#==============================================================================
|
91
90
|
def calc_sharpe_ratio(regdf):
|
@@ -101,8 +100,9 @@ def calc_sharpe_ratio(regdf):
|
|
101
100
|
#计算夏普指数
|
102
101
|
sr=ret_rf_mean/ret_rf_std
|
103
102
|
|
104
|
-
|
105
|
-
|
103
|
+
rp_mean=ret_rf_mean
|
104
|
+
beta=False
|
105
|
+
return sr,rp_mean,beta
|
106
106
|
|
107
107
|
if __name__=='__main__':
|
108
108
|
rfd=rf_daily_china('2021-10-1','2021-11-28',rate_period='1Y',rate_type='shibor')
|
@@ -131,15 +131,18 @@ def calc_sortino_ratio(regdf):
|
|
131
131
|
#计算索梯诺指数
|
132
132
|
sr=ret_rf_mean/ret_rf_lpsd
|
133
133
|
|
134
|
-
|
135
|
-
|
134
|
+
rp_mean=ret_rf_mean
|
135
|
+
beta=False
|
136
|
+
return sr,rp_mean,beta
|
136
137
|
|
137
138
|
#==============================================================================
|
138
|
-
def print_rar_ratio(regdf,portfolio,
|
139
|
+
def print_rar_ratio(regdf,portfolio,rp_mean,beta,ratio_name,ratio):
|
139
140
|
"""
|
140
141
|
功能:打印风险调整后的收益率
|
141
|
-
|
142
|
+
输入:数据框,投资组合构成,收益溢价均值,贝塔系数,指数名称,指数
|
142
143
|
输出:打印
|
144
|
+
|
145
|
+
注意:若贝塔系数为False则不打印
|
143
146
|
"""
|
144
147
|
|
145
148
|
#从字典中提取信息
|
@@ -151,31 +154,40 @@ def print_rar_ratio(regdf,portfolio,ret_mean,ratio_name,ratio):
|
|
151
154
|
date_end=str(regdf.index[-1].year)+'-'+str(regdf.index[-1].month)+ \
|
152
155
|
'-'+str(regdf.index[-1].day)
|
153
156
|
print("\n======== 风险调整收益率 ========")
|
154
|
-
print("
|
157
|
+
print("证券资产:",portfolio_name(portfolio))
|
158
|
+
#print("市场指数:",ectranslate(scope),'\b,',ticker_name(mktidx))
|
159
|
+
print("市场指数:",ticker_name(mktidx))
|
155
160
|
#print("成分股 :",ticker_name(stocklist))
|
156
161
|
#print("持仓权重:",portionlist)
|
157
162
|
print("样本期间:",date_start,"至",date_end)
|
158
163
|
"""
|
159
164
|
print("日均收益率:",round(ret_mean,4),'\b%')
|
160
|
-
"""
|
161
165
|
annual_ret=(1+ret_mean/100)**252-1
|
162
166
|
print("年化收益率:",round(annual_ret,4))
|
163
|
-
|
164
|
-
|
167
|
+
"""
|
168
|
+
if not isinstance(beta,bool):
|
169
|
+
print("贝塔系数:",round(beta,4))
|
170
|
+
|
171
|
+
print("风险溢价均值%:",round(rp_mean,4))
|
165
172
|
|
173
|
+
#print(ratio_name.capitalize(),"\b比率:",round(ratio,4),'\b%')
|
174
|
+
print(ratio_name.capitalize(),"\b比率%:",round(ratio,4))
|
175
|
+
"""
|
166
176
|
print("***投资组合构成:")
|
167
177
|
print_tickerlist_sharelist(stocklist,portionlist,2)
|
168
|
-
|
178
|
+
"""
|
169
179
|
|
170
|
-
import datetime as dt;
|
171
|
-
print("数据来源:新浪/stooq
|
180
|
+
import datetime as dt; todaydt=dt.date.today()
|
181
|
+
print("数据来源:新浪/stooq, "+str(todaydt))
|
172
182
|
|
173
183
|
return
|
174
184
|
#==============================================================================
|
175
185
|
if __name__=='__main__':
|
176
|
-
|
177
|
-
|
178
|
-
|
186
|
+
portfolio={'Market':('US','^GSPC'),'AAPL':0.5,'MSFT':0.3,'IBM':0.2}
|
187
|
+
start='2024-6-1'
|
188
|
+
end='2025-5-30'
|
189
|
+
RF=0.04
|
190
|
+
printout=True
|
179
191
|
|
180
192
|
rate_period='ON'
|
181
193
|
|
@@ -200,31 +212,43 @@ def treynor_ratio_portfolio(portfolio,start,end,RF=True,printout=True):
|
|
200
212
|
|
201
213
|
#从字典中提取信息
|
202
214
|
scope,mktidx,stocklist,portionlist,ticker_type=decompose_portfolio(portfolio)
|
215
|
+
|
216
|
+
#第2步:获得无风险收益率/市场收益率序列
|
217
|
+
#获得期间的日无风险收益率(抓取的RF为百分比)
|
218
|
+
if isinstance(RF,bool):
|
219
|
+
print(" Searching for risk-free interest rate ...")
|
220
|
+
if scope=='China':
|
221
|
+
rf_df=get_mkt_rf_daily_china(mktidx,start,end,rate_period='1Y',rate_type='shibor',RF=RF)
|
222
|
+
else:
|
223
|
+
rf_df=get_rf(start,end,scope=scope,freq='daily')
|
224
|
+
if rf_df is None:
|
225
|
+
message=" #Error("+func_name+"): "+"no data available for rf in"
|
226
|
+
print(message,scope,start,end)
|
227
|
+
return None,None
|
228
|
+
RF=rf_df['RF'].mean()
|
203
229
|
|
204
|
-
#第
|
205
|
-
|
206
|
-
sp=get_portfolio_prices(portfolio,start,end)
|
230
|
+
#第3步:计算投资组合的日收益率序列
|
231
|
+
#抓取日投资组合价格:内含Mkt-RF和RF
|
232
|
+
sp=get_portfolio_prices(portfolio,start,end,RF=RF)
|
207
233
|
#计算日收益率,表示为百分比
|
234
|
+
"""
|
208
235
|
import pandas as pd
|
209
236
|
ret_pf=pd.DataFrame(sp['Close'].pct_change())*100.0
|
210
237
|
ret_pf=ret_pf.dropna()
|
211
|
-
|
212
|
-
|
213
|
-
#获得期间的日无风险收益率(抓取的RF为百分比)
|
214
|
-
print(" Searching for risk-free interest rate ...")
|
215
|
-
if scope=='China':
|
216
|
-
rf_df=get_mkt_rf_daily_china(mktidx,start,end,rate_period='1Y',rate_type='shibor',RF=RF)
|
217
|
-
else:
|
218
|
-
rf_df=get_rf(start,end,scope=scope,freq='daily')
|
219
|
-
if rf_df is None:
|
220
|
-
message=" #Error("+func_name+"): "+"no data available for rf in"
|
221
|
-
print(message,scope,start,end)
|
222
|
-
return None,None
|
238
|
+
"""
|
239
|
+
ret_pf=sp
|
223
240
|
|
224
241
|
#第4步:合并投资组合日收益率与无风险利率/市场收益率序列
|
225
|
-
|
226
|
-
|
242
|
+
"""
|
243
|
+
if isinstance(RF,bool):
|
244
|
+
#合并rf_df与ret_pf
|
245
|
+
reg=pd.merge(ret_pf,rf_df,how='inner',left_index=True,right_index=True)
|
246
|
+
else:
|
247
|
+
reg=ret_pf
|
248
|
+
reg['RF']=RF/365 #日度无风险收益率%
|
227
249
|
reg['Ret-RF']=reg['Close']-reg['RF']
|
250
|
+
"""
|
251
|
+
reg=ret_pf
|
228
252
|
reg=reg.dropna()
|
229
253
|
if len(reg) == 0:
|
230
254
|
message=" #Error("+func_name+"): "+"empty ret-rf data for regression"
|
@@ -233,14 +257,14 @@ def treynor_ratio_portfolio(portfolio,start,end,RF=True,printout=True):
|
|
233
257
|
|
234
258
|
#第5步:计算风险调整后的收益率
|
235
259
|
##########风险调整后的收益率,计算开始##########
|
236
|
-
tr,
|
260
|
+
tr,rp_mean,beta=calc_treynor_ratio(reg)
|
237
261
|
##########风险调整后的收益率,计算结束##########
|
238
262
|
|
239
263
|
#第6步:打印结果
|
240
264
|
if printout == True:
|
241
|
-
print_rar_ratio(reg,portfolio,
|
265
|
+
print_rar_ratio(reg,portfolio,rp_mean,beta,ratio_name,tr)
|
242
266
|
|
243
|
-
return tr,
|
267
|
+
return tr,rp_mean
|
244
268
|
|
245
269
|
|
246
270
|
if __name__=='__main__':
|
@@ -258,11 +282,13 @@ if __name__=='__main__':
|
|
258
282
|
indicator='alpha'
|
259
283
|
|
260
284
|
|
261
|
-
def rar_ratio_portfolio(portfolio,start,end
|
285
|
+
def rar_ratio_portfolio(portfolio,start='MRY',end='today', \
|
286
|
+
indicator='sharpe', \
|
287
|
+
RF=0,printout=True):
|
262
288
|
"""
|
263
289
|
功能:按天计算一个投资组合的风险调整后的收益率指数
|
264
290
|
投资组合的结构:{'Market':('US','^GSPC'),'AAPL':0.5,'MSFT':0.3,'IBM':0.2}
|
265
|
-
|
291
|
+
输入:投资组合,开始日期,结束日期,rar种类
|
266
292
|
输出:风险调整后的收益率指数
|
267
293
|
"""
|
268
294
|
ratio_name=indicator
|
@@ -276,13 +302,16 @@ def rar_ratio_portfolio(portfolio,start,end,indicator='sharpe',RF=0,printout=Tru
|
|
276
302
|
if ratio_name not in ratio_list:
|
277
303
|
message=" #Error("+func_name+"): "+"unsupported rar ratio type"
|
278
304
|
print(message)
|
279
|
-
return None,None
|
305
|
+
return None,None
|
306
|
+
|
307
|
+
start,end=start_end_preprocess(start,end)
|
280
308
|
result,startdate,enddate=check_period(start,end)
|
281
309
|
if not result:
|
282
310
|
message=" #Error("+func_name+"): "+"invalid start or end date"
|
283
311
|
print(message,start,end)
|
284
312
|
return None,None
|
285
313
|
|
314
|
+
print(f" Calculating {ratio_name} ratio ...")
|
286
315
|
#从字典中提取信息
|
287
316
|
scope,mktidx,stocklist,portionlist,ticker_type=decompose_portfolio(portfolio)
|
288
317
|
|
@@ -307,8 +336,19 @@ def rar_ratio_portfolio(portfolio,start,end,indicator='sharpe',RF=0,printout=Tru
|
|
307
336
|
rf_value_flag=True
|
308
337
|
|
309
338
|
#第3步:计算投资组合的日收益率序列
|
339
|
+
import os,sys
|
340
|
+
class HiddenPrints:
|
341
|
+
def __enter__(self):
|
342
|
+
self._original_stdout = sys.stdout
|
343
|
+
sys.stdout = open(os.devnull, 'w')
|
344
|
+
|
345
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
346
|
+
sys.stdout.close()
|
347
|
+
sys.stdout = self._original_stdout
|
348
|
+
|
310
349
|
#抓取日投资组合价格
|
311
|
-
|
350
|
+
with HiddenPrints():
|
351
|
+
sp=get_portfolio_prices(portfolio,startdate,enddate,RF=RF)
|
312
352
|
if sp is None:
|
313
353
|
print(" #Error(rar_ratio_portfolio): failed to retrieve portfolio information")
|
314
354
|
return None,None
|
@@ -339,17 +379,17 @@ def rar_ratio_portfolio(portfolio,start,end,indicator='sharpe',RF=0,printout=Tru
|
|
339
379
|
print(message)
|
340
380
|
return None,None
|
341
381
|
|
342
|
-
#第
|
382
|
+
#第4步:计算风险调整后的收益率
|
343
383
|
##########风险调整后的收益率,计算开始##########
|
344
384
|
calc_func='calc_'+ratio_name+'_ratio'
|
345
|
-
rar,
|
385
|
+
rar,rp_mean,beta=eval(calc_func)(reg)
|
346
386
|
##########风险调整后的收益率,计算结束##########
|
347
387
|
|
348
|
-
#第
|
388
|
+
#第5步:打印结果
|
349
389
|
if printout == True:
|
350
|
-
print_rar_ratio(reg,portfolio,
|
390
|
+
print_rar_ratio(reg,portfolio,rp_mean,beta,ratio_name,rar)
|
351
391
|
|
352
|
-
return rar,
|
392
|
+
return rar,rp_mean
|
353
393
|
|
354
394
|
|
355
395
|
if __name__=='__main__':
|
@@ -366,7 +406,7 @@ if __name__=='__main__':
|
|
366
406
|
window=30
|
367
407
|
graph=True
|
368
408
|
|
369
|
-
def rar_ratio_rolling(portfolio,start,end,indicator='sharpe',RF=0, \
|
409
|
+
def rar_ratio_rolling(portfolio,start='MRY',end='today',indicator='sharpe',RF=0, \
|
370
410
|
window=21,graph=True,source='auto'):
|
371
411
|
"""
|
372
412
|
功能:滚动计算一个投资组合的风险调整后的收益率指数
|
@@ -378,7 +418,9 @@ def rar_ratio_rolling(portfolio,start,end,indicator='sharpe',RF=0, \
|
|
378
418
|
|
379
419
|
注意:当RF=False时有bug
|
380
420
|
"""
|
381
|
-
|
421
|
+
start,end=start_end_preprocess(start,end)
|
422
|
+
|
423
|
+
ratio_name=indicator.lower()
|
382
424
|
|
383
425
|
#第1步:各种准备和检查工作
|
384
426
|
print(" Start to calculate rar ratios, please wait ...")
|
@@ -459,7 +501,7 @@ def rar_ratio_rolling(portfolio,start,end,indicator='sharpe',RF=0, \
|
|
459
501
|
print(message)
|
460
502
|
return None,None
|
461
503
|
|
462
|
-
#第
|
504
|
+
#第4步:滚动计算风险调整后的收益率
|
463
505
|
##########风险调整后的收益率,计算开始##########
|
464
506
|
#用于保存rar和ret_rf_mean
|
465
507
|
import pandas as pd
|
@@ -496,7 +538,7 @@ def rar_ratio_rolling(portfolio,start,end,indicator='sharpe',RF=0, \
|
|
496
538
|
rars.set_index(['Date'],inplace=True)
|
497
539
|
##########风险调整后的收益率,计算结束##########
|
498
540
|
|
499
|
-
#第
|
541
|
+
#第5步:绘图
|
500
542
|
if graph == True:
|
501
543
|
print(" Rendering graphics ...")
|
502
544
|
draw_rar_ratio(rars,portfolio,ratio_name,pname)
|
@@ -605,35 +647,43 @@ def sharpe_ratio_portfolio(portfolio,start,end,RF=True,printout=True):
|
|
605
647
|
return None,None
|
606
648
|
"""
|
607
649
|
|
608
|
-
|
609
|
-
|
650
|
+
#获得期间的无风险收益率
|
651
|
+
if isinstance(RF,bool):
|
652
|
+
print(" Searching for risk-free interest rate ...")
|
653
|
+
if scope=='China':
|
654
|
+
rf_df=get_mkt_rf_daily_china(mktidx,start,end,rate_period='1Y',rate_type='shibor',RF=RF)
|
655
|
+
else:
|
656
|
+
rf_df=get_rf(start,end,scope=scope,freq='daily')
|
657
|
+
if rf_df is None:
|
658
|
+
message=" #Error("+func_name+"): "+"no data available for rf in"
|
659
|
+
print(message,scope,start,end)
|
660
|
+
return None,None
|
661
|
+
RF=rf_df['RF'].mean()
|
662
|
+
|
663
|
+
#抓取日投资组合价格:内含Mkt-RF和RF
|
664
|
+
sp=get_portfolio_prices(portfolio,start,end,RF=RF)
|
610
665
|
#计算日收益率,表示为百分比
|
666
|
+
"""
|
611
667
|
import pandas as pd
|
612
668
|
ret_pf=pd.DataFrame(sp['Close'].pct_change())*100.0
|
669
|
+
"""
|
670
|
+
ret_pf=sp
|
613
671
|
ret_pf=ret_pf.dropna()
|
614
|
-
|
615
|
-
#获得期间的无风险收益率
|
616
|
-
print(" Searching for risk-free interest rate ...")
|
617
|
-
if scope=='China':
|
618
|
-
rf_df=get_mkt_rf_daily_china(mktidx,start,end,rate_period='1Y',rate_type='shibor',RF=RF)
|
619
|
-
else:
|
620
|
-
rf_df=get_rf(start,end,scope=scope,freq='daily')
|
621
|
-
if rf_df is None:
|
622
|
-
message=" #Error("+func_name+"): "+"no data available for rf in"
|
623
|
-
print(message,scope,start,end)
|
624
|
-
return None,None
|
625
672
|
|
626
673
|
#强制转换索引格式,彻底消除下面并表的潜在隐患
|
674
|
+
"""
|
627
675
|
rf_df['ffdate']=rf_df.index.astype('str')
|
628
676
|
rf_df['ffdate']=pd.to_datetime(rf_df['ffdate'])
|
629
677
|
rf_df.set_index(['ffdate'],inplace=True)
|
630
|
-
|
678
|
+
"""
|
679
|
+
"""
|
631
680
|
#合并rf_df与ret_pf
|
632
681
|
reg=pd.merge(ret_pf,rf_df,how='inner',left_index=True,right_index=True)
|
633
682
|
reg['Ret-RF']=reg['Close']-reg['RF']
|
634
683
|
reg=reg.dropna()
|
635
|
-
|
684
|
+
"""
|
636
685
|
#计算风险溢价Ret-RF均值和标准差
|
686
|
+
reg=ret_pf
|
637
687
|
ret_rf_mean=reg['Ret-RF'].mean()
|
638
688
|
ret_rf_std=reg['Ret-RF'].std()
|
639
689
|
|
@@ -647,20 +697,23 @@ def sharpe_ratio_portfolio(portfolio,start,end,RF=True,printout=True):
|
|
647
697
|
date_end=str(reg.index[-1].year)+'-'+str(reg.index[-1].month)+ \
|
648
698
|
'-'+str(reg.index[-1].day)
|
649
699
|
print("\n===== 风险调整收益率 =====")
|
650
|
-
|
700
|
+
"""
|
651
701
|
_,_,tickerlist,sharelist,ticker_type=decompose_portfolio(portfolio)
|
652
702
|
if len(tickerlist)==1:
|
653
703
|
product=str(ticker_name(tickerlist,'bond'))
|
654
704
|
else:
|
655
705
|
product=str(ticker_name(tickerlist,'bond'))+' by '+str(sharelist)
|
656
|
-
|
657
|
-
print("
|
658
|
-
print("
|
659
|
-
print("
|
706
|
+
"""
|
707
|
+
print("证券资产:",portfolio_name(portfolio))
|
708
|
+
print("样本期间:",date_start,"至",date_end,"(可用日期)")
|
709
|
+
print("风险溢价均值%:",round(ret_rf_mean,4))
|
710
|
+
print("风险溢价标准差%:",round(ret_rf_std,4))
|
711
|
+
print("夏普比率%:",round(sr,4))
|
660
712
|
import datetime as dt; today=dt.date.today()
|
661
713
|
print("*数据来源:新浪/stooq/FRED,"+str(today))
|
662
714
|
|
663
|
-
|
715
|
+
beta=False
|
716
|
+
return sr,ret_rf_mean,beta
|
664
717
|
|
665
718
|
|
666
719
|
if __name__=='__main__':
|
@@ -700,24 +753,28 @@ def sortino_ratio_portfolio(portfolio,start,end,RF=True,printout=True):
|
|
700
753
|
return None,None
|
701
754
|
"""
|
702
755
|
|
756
|
+
#获得期间的无风险收益率
|
757
|
+
if isinstance(RF,bool):
|
758
|
+
print(" Searching for risk-free interest rate ...")
|
759
|
+
if scope=='China':
|
760
|
+
rf_df=get_mkt_rf_daily_china(mktidx,start,end,rate_period='1Y',rate_type='shibor',RF=RF)
|
761
|
+
else:
|
762
|
+
rf_df=get_rf(start,end,scope=scope,freq='daily')
|
763
|
+
if rf_df is None:
|
764
|
+
message=" #Error("+func_name+"): "+"no data available for rf in"
|
765
|
+
print(message,scope,start,end)
|
766
|
+
return None,None
|
767
|
+
RF=rf_df['RF'].mean()
|
768
|
+
|
703
769
|
#抓取日投资组合价格
|
704
|
-
sp=get_portfolio_prices(portfolio,start,end)
|
770
|
+
sp=get_portfolio_prices(portfolio,start,end,RF=RF)
|
771
|
+
ret_pf=sp
|
772
|
+
"""
|
705
773
|
#计算日收益率,表示为百分比
|
706
774
|
import pandas as pd
|
707
775
|
ret_pf=pd.DataFrame(sp['Close'].pct_change())*100.0
|
708
776
|
ret_pf=ret_pf.dropna()
|
709
777
|
|
710
|
-
#获得期间的无风险收益率
|
711
|
-
print(" Searching for risk-free interest rate ...")
|
712
|
-
if scope=='China':
|
713
|
-
rf_df=get_mkt_rf_daily_china(mktidx,start,end,rate_period='1Y',rate_type='shibor',RF=RF)
|
714
|
-
else:
|
715
|
-
rf_df=get_rf(start,end,scope=scope,freq='daily')
|
716
|
-
if rf_df is None:
|
717
|
-
message=" #Error("+func_name+"): "+"no data available for rf in"
|
718
|
-
print(message,scope,start,end)
|
719
|
-
return None,None
|
720
|
-
|
721
778
|
#强制转换索引格式,彻底消除下面并表的潜在隐患
|
722
779
|
rf_df['ffdate']=rf_df.index.astype('str')
|
723
780
|
rf_df['ffdate']=pd.to_datetime(rf_df['ffdate'])
|
@@ -726,6 +783,8 @@ def sortino_ratio_portfolio(portfolio,start,end,RF=True,printout=True):
|
|
726
783
|
#合并rf_df与ret_pf
|
727
784
|
reg=pd.merge(ret_pf,rf_df,how='inner',left_index=True,right_index=True)
|
728
785
|
reg['Ret-RF']=reg['Close']-reg['RF']
|
786
|
+
"""
|
787
|
+
reg=ret_pf
|
729
788
|
reg=reg.dropna()
|
730
789
|
|
731
790
|
#计算风险溢价Ret-RF均值和下偏标准差LPSD
|
@@ -743,17 +802,18 @@ def sortino_ratio_portfolio(portfolio,start,end,RF=True,printout=True):
|
|
743
802
|
date_end=str(reg.index[-1].year)+'-'+str(reg.index[-1].month)+ \
|
744
803
|
'-'+str(reg.index[-1].day)
|
745
804
|
print("\n===== 风险调整收益率 =====")
|
746
|
-
|
805
|
+
"""
|
747
806
|
_,_,tickerlist,sharelist,ticker_type=decompose_portfolio(portfolio)
|
748
807
|
if len(tickerlist)==1:
|
749
808
|
product=str(ticker_name(tickerlist,'bond'))
|
750
809
|
else:
|
751
810
|
product=str(ticker_name(tickerlist,'bond'))+' by '+str(sharelist)
|
752
|
-
|
753
|
-
print("
|
754
|
-
|
755
|
-
print("
|
756
|
-
print("
|
811
|
+
"""
|
812
|
+
print("证券资产:",portfolio_name(portfolio))
|
813
|
+
print("样本期间:",date_start,"至",date_end,"(可用日期)")
|
814
|
+
print("风险溢价均值%:",round(ret_rf_mean,4))
|
815
|
+
print("下偏标准差%:",round(ret_rf_lpsd,4))
|
816
|
+
print("索替诺比率%:",round(sr,4))
|
757
817
|
|
758
818
|
import datetime as dt; today=dt.date.today()
|
759
819
|
print("*数据来源:新浪/stooq/FRED,"+str(today))
|
@@ -797,24 +857,28 @@ def jensen_alpha_portfolio(portfolio,start,end,RF=True,printout=True):
|
|
797
857
|
return None,None
|
798
858
|
"""
|
799
859
|
|
800
|
-
|
801
|
-
|
860
|
+
#获得期间的无风险收益率
|
861
|
+
if isinstance(RF,bool):
|
862
|
+
print(" Searching for risk-free interest rate ...")
|
863
|
+
if scope=='China':
|
864
|
+
rf_df=get_mkt_rf_daily_china(mktidx,start,end,rate_period='1Y',rate_type='shibor',RF=RF)
|
865
|
+
else:
|
866
|
+
rf_df=get_rf(start,end,scope=scope,freq='daily')
|
867
|
+
if rf_df is None:
|
868
|
+
message=" #Error("+func_name+"): "+"no data available for rf in"
|
869
|
+
print(message,scope,start,end)
|
870
|
+
return None,None
|
871
|
+
RF=rf_df['RF'].mean()
|
872
|
+
|
873
|
+
#抓取日投资组合价格:内含Mkt-RF和RF
|
874
|
+
sp=get_portfolio_prices(portfolio,start,end,RF=RF)
|
802
875
|
#计算日收益率,表示为百分比
|
876
|
+
ret_pf=sp
|
877
|
+
"""
|
803
878
|
import pandas as pd
|
804
879
|
ret_pf=pd.DataFrame(sp['Close'].pct_change())*100.0
|
805
880
|
ret_pf=ret_pf.dropna()
|
806
881
|
|
807
|
-
#获得期间的无风险收益率
|
808
|
-
print(" Searching for risk-free interest rate ...")
|
809
|
-
if scope=='China':
|
810
|
-
rf_df=get_mkt_rf_daily_china(mktidx,start,end,rate_period='1Y',rate_type='shibor',RF=RF)
|
811
|
-
else:
|
812
|
-
rf_df=get_rf(start,end,scope=scope,freq='daily')
|
813
|
-
if rf_df is None:
|
814
|
-
message=" #Error("+func_name+"): "+"no data available for rf in"
|
815
|
-
print(message,scope,start,end)
|
816
|
-
return None,None
|
817
|
-
|
818
882
|
#强制转换索引格式,彻底消除下面并表的潜在隐患
|
819
883
|
rf_df['ffdate']=rf_df.index.astype('str')
|
820
884
|
rf_df['ffdate']=pd.to_datetime(rf_df['ffdate'])
|
@@ -830,6 +894,8 @@ def jensen_alpha_portfolio(portfolio,start,end,RF=True,printout=True):
|
|
830
894
|
#合并rf_df与ret_pf
|
831
895
|
reg=pd.merge(ret_pf,rf_df,how='inner',left_index=True,right_index=True)
|
832
896
|
reg['Ret-RF']=reg['Close']-reg['RF']
|
897
|
+
"""
|
898
|
+
reg=ret_pf
|
833
899
|
reg=reg.dropna()
|
834
900
|
if len(reg) == 0:
|
835
901
|
print(" #Error(jensen_alpha_portfolio): empty data for regression.")
|
@@ -848,21 +914,23 @@ def jensen_alpha_portfolio(portfolio,start,end,RF=True,printout=True):
|
|
848
914
|
date_end=str(reg.index[-1].year)+'-'+str(reg.index[-1].month)+ \
|
849
915
|
'-'+str(reg.index[-1].day)
|
850
916
|
print("\n===== 风险调整收益率 =====")
|
851
|
-
|
917
|
+
"""
|
852
918
|
_,_,tickerlist,sharelist,ticker_type=decompose_portfolio(portfolio)
|
853
919
|
if len(tickerlist)==1:
|
854
920
|
product=str(ticker_name(tickerlist,'bond'))
|
855
921
|
else:
|
856
922
|
product=str(ticker_name(tickerlist,'bond'))+' by '+str(sharelist)
|
857
|
-
|
858
|
-
print("
|
859
|
-
print("
|
860
|
-
print("
|
923
|
+
"""
|
924
|
+
print("证券资产:",portfolio_name(portfolio))
|
925
|
+
print("样本期间:",date_start,"至",date_end,"(可用日期)")
|
926
|
+
print("贝塔系数:",round(beta,4))
|
927
|
+
print("风险溢价均值%:",round(ret_rf_mean,4))
|
928
|
+
print("詹森阿尔法%:",round(alpha,4))
|
861
929
|
|
862
930
|
import datetime as dt; today=dt.date.today()
|
863
931
|
print("*数据来源:新浪/stooq/FRED,"+str(today))
|
864
932
|
|
865
|
-
return alpha,ret_rf_mean
|
933
|
+
return alpha,ret_rf_mean,beta
|
866
934
|
|
867
935
|
|
868
936
|
if __name__=='__main__':
|