siat 3.10.24__py3-none-any.whl → 3.10.75__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/bond.py +57 -23
- siat/capm_beta.py +2 -1
- siat/capm_beta2.py +34 -3
- siat/common.py +7 -1
- siat/economy.py +3 -3
- siat/fama_french.py +99 -8
- siat/financials.py +52 -16
- siat/fund_china.py +46 -17
- siat/future_china.py +47 -59
- siat/grafix.py +218 -155
- siat/market_china.py +2 -1
- siat/option_china.py +49 -15
- siat/option_pricing.py +13 -6
- siat/risk_adjusted_return.py +105 -54
- siat/risk_adjusted_return2.py +3 -1
- siat/risk_evaluation.py +46 -5
- siat/sector_china.py +12 -2
- siat/security_prices.py +16 -15
- siat/security_trend2.py +11 -11
- siat/stock.py +6 -3
- siat/stock_china.py +26 -8
- siat/translate.py +2 -1
- {siat-3.10.24.dist-info → siat-3.10.75.dist-info}/METADATA +1 -1
- {siat-3.10.24.dist-info → siat-3.10.75.dist-info}/RECORD +27 -27
- {siat-3.10.24.dist-info → siat-3.10.75.dist-info}/LICENSE +0 -0
- {siat-3.10.24.dist-info → siat-3.10.75.dist-info}/WHEEL +0 -0
- {siat-3.10.24.dist-info → siat-3.10.75.dist-info}/top_level.txt +0 -0
siat/option_china.py
CHANGED
@@ -40,7 +40,7 @@ def option_comm_dict_china(symbol="玉米期权"):
|
|
40
40
|
try:
|
41
41
|
#optiondict=ak.option_sina_commodity_dict(symbol=symbol)
|
42
42
|
optiondict=ak.option_commodity_contract_sina(symbol=symbol)
|
43
|
-
print("\n中国"+symbol+"
|
43
|
+
print("\n中国"+symbol+"的当前可用合约:")
|
44
44
|
#contractlist=optiondict[symbol]
|
45
45
|
contractlist=list(optiondict['合约'])
|
46
46
|
contractlist.sort(reverse=False)
|
@@ -61,11 +61,16 @@ if __name__=='__main__':
|
|
61
61
|
#==============================================================================
|
62
62
|
if __name__=='__main__':
|
63
63
|
symbol='黄金期权'
|
64
|
-
contract='
|
64
|
+
contract='au2508'
|
65
65
|
printout=True
|
66
66
|
graph=True
|
67
67
|
|
68
|
-
|
68
|
+
df=option_comm_china(symbol='黄金期权',contract='au2508')
|
69
|
+
|
70
|
+
def option_comm_china(symbol='',contract='', \
|
71
|
+
twinx=True,
|
72
|
+
loc1='upper left',loc2='upper right', \
|
73
|
+
printout=True,graph=True):
|
69
74
|
"""
|
70
75
|
获取中国商品期权大类
|
71
76
|
若symbol=''或错误且contract=''时显示中国商品期权大类
|
@@ -129,14 +134,21 @@ def option_comm_china(symbol='',contract='',printout=True,graph=True):
|
|
129
134
|
print(" \n中国"+symbol+contract+"的看跌期权合约:")
|
130
135
|
printlist(df2plist,numperline=6,beforehand=' '*4,separator=' ')
|
131
136
|
|
132
|
-
if
|
133
|
-
|
137
|
+
if graph:
|
138
|
+
if not (twinx in ['UD','LR']):
|
139
|
+
footnote="行权价-->\n\n"+"数据来源:新浪财经,"+str(today)
|
140
|
+
else:
|
141
|
+
footnote="行权价-->\n"+"数据来源:新浪财经,"+str(today)
|
134
142
|
|
135
|
-
print("\nRendering graphics
|
136
|
-
titletxt="
|
143
|
+
print("\nRendering graphics btw contract and strike prices...")
|
144
|
+
titletxt="期权价格与行权价的关系:"+symbol+contract
|
145
|
+
# maxticks为bool类型时表示横轴不能按照日期处理,否则会丢失数据成空图!!!
|
137
146
|
plot_line2(df2,"看涨期权",'最新价C','价格', \
|
138
147
|
df2,"看跌期权",'最新价P','价格', \
|
139
|
-
'价格',titletxt,footnote,power=0,
|
148
|
+
'价格',titletxt,footnote,power=0, \
|
149
|
+
twinx=twinx, \
|
150
|
+
loc1=loc1,loc2=loc2, \
|
151
|
+
maxticks=False)
|
140
152
|
"""
|
141
153
|
print("Rendering graphics for the relationships btw call price and open interest ...")
|
142
154
|
titletxt="当前期权价格与持仓量的关系:"+symbol+contract+'的'+"看涨期权"
|
@@ -988,15 +1000,22 @@ def option_fin_contracts(symbol,end_month,direction='call',printout=True):
|
|
988
1000
|
printdf=contracts[collist].copy()
|
989
1001
|
printdf.columns=collistcn
|
990
1002
|
|
1003
|
+
printdf.reset_index(drop=True,inplace=True)
|
1004
|
+
|
991
1005
|
#打印对齐
|
992
1006
|
pd.set_option('display.unicode.ambiguous_as_wide', True)
|
993
1007
|
pd.set_option('display.unicode.east_asian_width', True)
|
994
1008
|
pd.set_option('display.width', 180) # 设置打印宽度(**重要**)
|
995
1009
|
|
996
|
-
print(printdf.to_string(index=False))
|
1010
|
+
#print(printdf.to_string(index=False))
|
1011
|
+
|
1012
|
+
import datetime as dt; todaydt=str(dt.date.today())
|
1013
|
+
#print("\n来源:新浪/上交所/深交所/中金所,",today)
|
1014
|
+
footnote="数据来源:新浪/上交所/深交所/中金所, "+str(todaydt)
|
1015
|
+
df_display_CSS(printdf,titletxt='',footnote=footnote,facecolor='papayawhip', \
|
1016
|
+
first_col_align='center',second_col_align='center', \
|
1017
|
+
last_col_align='center',other_col_align='center')
|
997
1018
|
|
998
|
-
import datetime as dt; today=str(dt.date.today())
|
999
|
-
print("\n来源:新浪/上交所/深交所/中金所,",today)
|
1000
1019
|
|
1001
1020
|
return contracts
|
1002
1021
|
|
@@ -1852,12 +1871,14 @@ def hs300option_compare(option1,option2,loc1='best',loc2='best',twinx=False):
|
|
1852
1871
|
ticker1="期权1:"+option_description(option1)
|
1853
1872
|
else:
|
1854
1873
|
ticker1="期权1"
|
1874
|
+
#ticker1="期权1:"+option_description(option1)
|
1855
1875
|
colname1='SO Close_x'
|
1856
1876
|
|
1857
1877
|
if not twinx:
|
1858
1878
|
ticker2="期权2:"+option_description(option2)
|
1859
1879
|
else:
|
1860
1880
|
ticker2="期权2"
|
1881
|
+
#ticker2="期权2:"+option_description(option2)
|
1861
1882
|
colname2='SO Close_y'
|
1862
1883
|
|
1863
1884
|
ylabeltxt="期权价格"
|
@@ -1870,14 +1891,23 @@ def hs300option_compare(option1,option2,loc1='best',loc2='best',twinx=False):
|
|
1870
1891
|
import datetime; today = datetime.date.today()
|
1871
1892
|
footnote2="数据来源: 新浪财经/东方财富, "+str(today)
|
1872
1893
|
footnote=footnote1+footnote2
|
1873
|
-
|
1894
|
+
"""
|
1874
1895
|
plot2_line2(df12,ticker1,colname1,'', \
|
1875
1896
|
df12,ticker2,colname2,'', \
|
1876
1897
|
ylabeltxt,titletxt,footnote, \
|
1877
1898
|
twinx=twinx, \
|
1878
1899
|
loc1=loc1,loc2=loc2, \
|
1879
1900
|
date_range=False,date_freq=False)
|
1880
|
-
|
1901
|
+
"""
|
1902
|
+
plot_line2(df12,ticker1,colname1,'', \
|
1903
|
+
df12,ticker2,colname2,'', \
|
1904
|
+
ylabeltxt,titletxt,footnote, \
|
1905
|
+
twinx=twinx, \
|
1906
|
+
loc1=loc1,loc2=loc2, \
|
1907
|
+
#date_range=False,date_freq=False
|
1908
|
+
)
|
1909
|
+
|
1910
|
+
|
1881
1911
|
return df12
|
1882
1912
|
|
1883
1913
|
if __name__=='__main__':
|
@@ -2293,16 +2323,20 @@ def fin_option_risk_sse2(option,maturity,exercise,trade_date, \
|
|
2293
2323
|
import numpy as np
|
2294
2324
|
textupper=0.01
|
2295
2325
|
textlower=0.065
|
2326
|
+
#textlower=0.2
|
2327
|
+
|
2296
2328
|
for a,b in zip(x,yv): ##控制标签位置:横坐标,纵坐标
|
2297
2329
|
if b >= 0:
|
2298
2330
|
plt.text(a-0.2,b+textupper,'%.3f'%b,ha = 'center',va = 'bottom',fontsize=14)
|
2299
2331
|
else:
|
2300
|
-
plt.text(a-0.2,b-textlower,'%.3f'%b,ha = 'center',va = 'bottom',fontsize=14)
|
2332
|
+
#plt.text(a-0.2,b-textlower,'%.3f'%b,ha = 'center',va = 'bottom',fontsize=14)
|
2333
|
+
plt.text(a-0.2,b-textlower,'%.3f'%b,ha = 'center',va = 'top',fontsize=14)
|
2301
2334
|
for a,b in zip(x,ys):
|
2302
2335
|
if b >= 0:
|
2303
2336
|
plt.text(a+0.2,b+textupper,'%.3f'%b,ha = 'center',va = 'bottom',fontsize=14)
|
2304
2337
|
else:
|
2305
|
-
plt.text(a+0.2,b-textlower,'%.3f'%b,ha = 'center',va = 'bottom',fontsize=14)
|
2338
|
+
#plt.text(a+0.2,b-textlower,'%.3f'%b,ha = 'center',va = 'bottom',fontsize=14)
|
2339
|
+
plt.text(a+0.2,b-textlower,'%.3f'%b,ha = 'center',va = 'top',fontsize=14)
|
2306
2340
|
|
2307
2341
|
#绘制图片边框
|
2308
2342
|
c.spines['top'].set_visible(True)
|
siat/option_pricing.py
CHANGED
@@ -77,7 +77,9 @@ def bs_call(S0,X,Days,r0,sigma,printout=True):
|
|
77
77
|
r0:年化无风险利率(需要转化为连续计算的无风险利率)
|
78
78
|
Days:距离到期日的天数,需要转换为距离到期日的年数=距离到期日的天数/365
|
79
79
|
"""
|
80
|
-
from scipy import
|
80
|
+
from scipy import stats
|
81
|
+
from numpy import log,exp,sqrt
|
82
|
+
|
81
83
|
#Days为距离到期日的日历日天数
|
82
84
|
T=Days/365.
|
83
85
|
r=log(r0+1)
|
@@ -119,7 +121,7 @@ def bsm_call(S0,X,Days,r0,sigma,Days1=0,div1=0,printout=True):
|
|
119
121
|
Days1:红利发放时距离到期日的天数,需要转换为年数
|
120
122
|
div1:红利金额
|
121
123
|
"""
|
122
|
-
from
|
124
|
+
from numpy import log,exp
|
123
125
|
#Days1为距离到期日的日历日天数
|
124
126
|
T=Days/365.
|
125
127
|
T1=Days1/365.
|
@@ -164,7 +166,9 @@ def bs_put(S0,X,Days,r0,sigma,printout=True):
|
|
164
166
|
r0:年化无风险利率(需要转化为连续计算的无风险利率)
|
165
167
|
Days:距离到期日的天数,需要转换为距离到期日的年数=距离到期日的天数/365
|
166
168
|
"""
|
167
|
-
from scipy import
|
169
|
+
from scipy import stats
|
170
|
+
from numpy import log,exp,sqrt
|
171
|
+
|
168
172
|
#Days为距离到期日的日历日天数
|
169
173
|
T=Days/365.
|
170
174
|
r=log(r0+1)
|
@@ -206,7 +210,8 @@ def bsm_put(S0,X,Days,r0,sigma,Days1=0,div1=0,printout=True):
|
|
206
210
|
Days1:红利发放时距离到期日的天数,需要转换为年数
|
207
211
|
div1:红利金额
|
208
212
|
"""
|
209
|
-
from
|
213
|
+
from numpy import log,exp,sqrt
|
214
|
+
|
210
215
|
#Days为距离到期日的日历日天数
|
211
216
|
T=Days/365.
|
212
217
|
T1=Days1/365.
|
@@ -1058,7 +1063,8 @@ def binomial_american_call(S0,X,Days,r0,sigma,q0=0,steps=200,printout=True):
|
|
1058
1063
|
q0:年化红利收益率,由于美式期权可能提前行权,故不考虑发放日期
|
1059
1064
|
steps:二叉树的步骤
|
1060
1065
|
"""
|
1061
|
-
from
|
1066
|
+
from numpy import log,exp
|
1067
|
+
|
1062
1068
|
#Days1为距离到期日的日历日天数
|
1063
1069
|
t=Days/365.
|
1064
1070
|
r=log(r0+1)
|
@@ -1113,7 +1119,8 @@ def binomial_american_put(S0,X,Days,r0,sigma,q0=0,steps=200,printout=True):
|
|
1113
1119
|
q0:年化红利收益率,由于美式期权可能提前行权,故不考虑发放日期
|
1114
1120
|
steps:二叉树的步骤
|
1115
1121
|
"""
|
1116
|
-
from
|
1122
|
+
from numpy import log,exp
|
1123
|
+
|
1117
1124
|
#Days1为距离到期日的日历日天数
|
1118
1125
|
t=Days/365.
|
1119
1126
|
r=log(r0+1)
|
siat/risk_adjusted_return.py
CHANGED
@@ -150,11 +150,11 @@ def print_rar_ratio(regdf,portfolio,ret_mean,ratio_name,ratio):
|
|
150
150
|
'-'+str(regdf.index[0].day)
|
151
151
|
date_end=str(regdf.index[-1].year)+'-'+str(regdf.index[-1].month)+ \
|
152
152
|
'-'+str(regdf.index[-1].day)
|
153
|
-
print("\n
|
153
|
+
print("\n======== 风险调整收益率 ========")
|
154
154
|
print("市场指数:",ectranslate(scope),'\b,',ticker_name(mktidx))
|
155
155
|
#print("成分股 :",ticker_name(stocklist))
|
156
156
|
#print("持仓权重:",portionlist)
|
157
|
-
print("
|
157
|
+
print("样本期间:",date_start,"至",date_end)
|
158
158
|
"""
|
159
159
|
print("日均收益率:",round(ret_mean,4),'\b%')
|
160
160
|
"""
|
@@ -168,7 +168,7 @@ def print_rar_ratio(regdf,portfolio,ret_mean,ratio_name,ratio):
|
|
168
168
|
|
169
169
|
|
170
170
|
import datetime as dt; today=dt.date.today()
|
171
|
-
print("
|
171
|
+
print("数据来源:新浪/stooq/FRED, "+str(today))
|
172
172
|
|
173
173
|
return
|
174
174
|
#==============================================================================
|
@@ -250,24 +250,28 @@ if __name__=='__main__':
|
|
250
250
|
|
251
251
|
#==============================================================================
|
252
252
|
if __name__=='__main__':
|
253
|
-
portfolio={'Market':('US','^GSPC'),'EDU':0.
|
254
|
-
start='
|
255
|
-
end ='
|
256
|
-
|
253
|
+
portfolio={'Market':('US','^GSPC'),'EDU':0.6,'TAL':0.4}
|
254
|
+
start='2025-1-01'
|
255
|
+
end ='2025-5-30'
|
256
|
+
RF=0.04; printout=True
|
257
|
+
indicator='sharpe'
|
258
|
+
indicator='alpha'
|
257
259
|
|
258
260
|
|
259
|
-
def rar_ratio_portfolio(portfolio,start,end,
|
261
|
+
def rar_ratio_portfolio(portfolio,start,end,indicator='sharpe',RF=0,printout=True):
|
260
262
|
"""
|
261
263
|
功能:按天计算一个投资组合的风险调整后的收益率指数
|
262
264
|
投资组合的结构:{'Market':('US','^GSPC'),'AAPL':0.5,'MSFT':0.3,'IBM':0.2}
|
263
265
|
输入:投资组合,开始日期,结束日期
|
264
266
|
输出:风险调整后的收益率指数
|
265
267
|
"""
|
268
|
+
ratio_name=indicator
|
266
269
|
|
267
270
|
#第1步:各种准备和检查工作
|
268
271
|
#设定错误信息的函数名
|
269
272
|
func_name='rar_ratio_portfolio'
|
270
273
|
|
274
|
+
ratio_name=ratio_name.lower()
|
271
275
|
ratio_list=['treynor','sharpe','sortino','alpha']
|
272
276
|
if ratio_name not in ratio_list:
|
273
277
|
message=" #Error("+func_name+"): "+"unsupported rar ratio type"
|
@@ -281,31 +285,54 @@ def rar_ratio_portfolio(portfolio,start,end,ratio_name='treynor',RF=True,printou
|
|
281
285
|
|
282
286
|
#从字典中提取信息
|
283
287
|
scope,mktidx,stocklist,portionlist,ticker_type=decompose_portfolio(portfolio)
|
288
|
+
|
289
|
+
#第2步:获得无风险收益率/市场收益率序列
|
290
|
+
#获得期间的日无风险收益率(抓取的RF为百分比)
|
291
|
+
rf_value_flag=True #RF以数值形式给出
|
292
|
+
if isinstance(RF,bool):
|
293
|
+
rf_value_flag=False
|
294
|
+
if RF:
|
295
|
+
print(" Searching for risk-free interest rate ...")
|
296
|
+
if scope=='China':
|
297
|
+
rf_df=get_mkt_rf_daily_china(mktidx,start,end,rate_period='1Y',rate_type='shibor',RF=RF)
|
298
|
+
else:
|
299
|
+
rf_df=get_rf(start,end,scope=scope,freq='daily')
|
300
|
+
if rf_df is None:
|
301
|
+
message=" #Error("+func_name+"): "+"no data available for rf in"
|
302
|
+
print(message,scope,start,end)
|
303
|
+
return None,None
|
304
|
+
RF=rf_df['RF'].mean()
|
305
|
+
else:
|
306
|
+
RF=0
|
307
|
+
rf_value_flag=True
|
284
308
|
|
285
|
-
#第
|
309
|
+
#第3步:计算投资组合的日收益率序列
|
286
310
|
#抓取日投资组合价格
|
287
|
-
sp=get_portfolio_prices(portfolio,startdate,enddate)
|
311
|
+
sp=get_portfolio_prices(portfolio,startdate,enddate,RF=RF)
|
312
|
+
if sp is None:
|
313
|
+
print(" #Error(rar_ratio_portfolio): failed to retrieve portfolio information")
|
314
|
+
return None,None
|
315
|
+
if len(sp) == 0:
|
316
|
+
print(" #Error(rar_ratio_portfolio): no portfolio information found during the period")
|
317
|
+
return None,None
|
318
|
+
"""
|
288
319
|
#计算日收益率,表示为百分比
|
289
320
|
import pandas as pd
|
290
321
|
ret_pf=pd.DataFrame(sp['Close'].pct_change())*100.0
|
291
322
|
ret_pf=ret_pf.dropna()
|
292
|
-
|
293
|
-
#第3步:获得无风险收益率/市场收益率序列
|
294
|
-
#获得期间的日无风险收益率(抓取的RF为百分比)
|
295
|
-
print(" Searching for risk-free interest rate ...")
|
296
|
-
if scope=='China':
|
297
|
-
rf_df=get_mkt_rf_daily_china(mktidx,start,end,rate_period='1Y',rate_type='shibor',RF=RF)
|
298
|
-
else:
|
299
|
-
rf_df=get_rf(start,end,scope=scope,freq='daily')
|
300
|
-
if rf_df is None:
|
301
|
-
message=" #Error("+func_name+"): "+"no data available for rf in"
|
302
|
-
print(message,scope,start,end)
|
303
|
-
return None,None
|
304
323
|
|
305
324
|
#第4步:合并投资组合日收益率与无风险利率/市场收益率序列
|
306
|
-
|
307
|
-
|
325
|
+
if not rf_value_flag:
|
326
|
+
#合并rf_df与ret_pf
|
327
|
+
reg=pd.merge(ret_pf,rf_df,how='inner',left_index=True,right_index=True)
|
328
|
+
|
329
|
+
else:
|
330
|
+
ret_pf['RF']=RF
|
331
|
+
reg=ret_pf
|
332
|
+
|
308
333
|
reg['Ret-RF']=reg['Close']-reg['RF']
|
334
|
+
"""
|
335
|
+
reg=sp
|
309
336
|
reg=reg.dropna()
|
310
337
|
if len(reg) == 0:
|
311
338
|
message=" #Error("+func_name+"): "+"empty data for ratio calculation"
|
@@ -339,7 +366,7 @@ if __name__=='__main__':
|
|
339
366
|
window=30
|
340
367
|
graph=True
|
341
368
|
|
342
|
-
def rar_ratio_rolling(portfolio,start,end,
|
369
|
+
def rar_ratio_rolling(portfolio,start,end,indicator='sharpe',RF=0, \
|
343
370
|
window=21,graph=True,source='auto'):
|
344
371
|
"""
|
345
372
|
功能:滚动计算一个投资组合的风险调整后的收益率指数
|
@@ -351,6 +378,7 @@ def rar_ratio_rolling(portfolio,start,end,ratio_name='treynor',RF=True, \
|
|
351
378
|
|
352
379
|
注意:当RF=False时有bug
|
353
380
|
"""
|
381
|
+
ratio_name=indicator
|
354
382
|
|
355
383
|
#第1步:各种准备和检查工作
|
356
384
|
print(" Start to calculate rar ratios, please wait ...")
|
@@ -369,46 +397,67 @@ def rar_ratio_rolling(portfolio,start,end,ratio_name='treynor',RF=True, \
|
|
369
397
|
print(message,start,end)
|
370
398
|
return None
|
371
399
|
#估算数据提前量,重设开始日历日期
|
372
|
-
startdate_delta=int(window/
|
400
|
+
#startdate_delta=int(window/20*30)+30
|
401
|
+
startdate_delta=int(window/20*31)
|
373
402
|
startdate1=date_adjust(startdate, adjust=-startdate_delta)
|
374
403
|
|
375
404
|
#从字典中提取信息
|
376
405
|
scope,mktidx,stocklist,portionlist,ticker_type=decompose_portfolio(portfolio)
|
377
|
-
|
378
|
-
|
406
|
+
pname=portfolio_name(portfolio)
|
407
|
+
if pname == '': pname="投资组合"
|
408
|
+
|
409
|
+
#第2步:获得无风险收益率/市场收益率序列
|
410
|
+
#获得期间的日无风险收益率(抓取的RF为百分比)
|
411
|
+
rf_value_flag=True #RF以数值形式给出
|
412
|
+
if isinstance(RF,bool):
|
413
|
+
rf_value_flag=False
|
414
|
+
if RF:
|
415
|
+
print(" Searching for risk-free interest rate ...")
|
416
|
+
if scope=='China':
|
417
|
+
rf_df=get_mkt_rf_daily_china(mktidx,start,end,rate_period='1Y',rate_type='shibor',RF=RF)
|
418
|
+
else:
|
419
|
+
rf_df=get_rf(start,end,scope=scope,freq='daily')
|
420
|
+
if rf_df is None:
|
421
|
+
message=" #Error("+func_name+"): "+"no data available for rf in"
|
422
|
+
print(message,scope,start,end)
|
423
|
+
return None,None
|
424
|
+
RF=rf_df['RF'].mean()
|
425
|
+
else:
|
426
|
+
RF=0
|
427
|
+
rf_value_flag=True
|
428
|
+
|
429
|
+
#第3步:计算投资组合的日收益率序列
|
379
430
|
#抓取日投资组合价格
|
380
|
-
sp=get_portfolio_prices(portfolio,startdate1,enddate,
|
381
|
-
if sp is None:
|
382
|
-
|
383
|
-
|
384
|
-
|
431
|
+
sp=get_portfolio_prices(portfolio,startdate1,enddate,RF=RF)
|
432
|
+
if sp is None:
|
433
|
+
print(" #Error(rar_ratio_portfolio): failed to retrieve portfolio information")
|
434
|
+
return None,None
|
435
|
+
if len(sp) == 0:
|
436
|
+
print(" #Error(rar_ratio_portfolio): no portfolio information found during the period")
|
437
|
+
return None,None
|
438
|
+
"""
|
385
439
|
#计算日收益率,表示为百分比
|
386
440
|
import pandas as pd
|
387
441
|
ret_pf=pd.DataFrame(sp['Close'].pct_change())*100.0
|
388
442
|
ret_pf=ret_pf.dropna()
|
389
|
-
|
390
|
-
#第3步:获得无风险收益率/市场收益率序列
|
391
|
-
#获得期间的日无风险收益率(抓取的RF为百分比)
|
392
|
-
#print(" Searching for risk-free interest rate ...")
|
393
|
-
if scope=='China':
|
394
|
-
rf_df=get_mkt_rf_daily_china(mktidx,start,end,rate_period='1Y',rate_type='shibor',RF=RF)
|
395
|
-
else:
|
396
|
-
rf_df=get_rf(start,end,scope=scope,freq='daily')
|
397
|
-
if rf_df is None:
|
398
|
-
message=" #Error("+func_name+"): "+"no data available for rf in"
|
399
|
-
print(message,scope,start,end)
|
400
|
-
return None,None
|
401
443
|
|
402
444
|
#第4步:合并投资组合日收益率与无风险利率/市场收益率序列
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
445
|
+
if not rf_value_flag:
|
446
|
+
#合并rf_df与ret_pf
|
447
|
+
reg=pd.merge(ret_pf,rf_df,how='inner',left_index=True,right_index=True)
|
448
|
+
|
449
|
+
else:
|
450
|
+
ret_pf['RF']=RF
|
451
|
+
reg=ret_pf
|
409
452
|
|
410
453
|
reg['Ret-RF']=reg['Close']-reg['RF']
|
454
|
+
"""
|
455
|
+
reg=sp
|
411
456
|
reg=reg.dropna()
|
457
|
+
if len(reg) == 0:
|
458
|
+
message=" #Error("+func_name+"): "+"empty data for ratio calculation"
|
459
|
+
print(message)
|
460
|
+
return None,None
|
412
461
|
|
413
462
|
#第5步:滚动计算风险调整后的收益率
|
414
463
|
##########风险调整后的收益率,计算开始##########
|
@@ -450,7 +499,7 @@ def rar_ratio_rolling(portfolio,start,end,ratio_name='treynor',RF=True, \
|
|
450
499
|
#第6步:绘图
|
451
500
|
if graph == True:
|
452
501
|
print(" Rendering graphics ...")
|
453
|
-
draw_rar_ratio(rars,portfolio,ratio_name)
|
502
|
+
draw_rar_ratio(rars,portfolio,ratio_name,pname)
|
454
503
|
|
455
504
|
return rars
|
456
505
|
|
@@ -459,7 +508,7 @@ if __name__=='__main__':
|
|
459
508
|
pf1={'Market':('US','^GSPC'),'AAPL':0.5,'MSFT':0.3,'IBM':0.2}
|
460
509
|
rars1=rar_ratio_rolling(pf1,'2020-1-1','2020-12-31',ratio_name='sharpe')
|
461
510
|
#==============================================================================
|
462
|
-
def draw_rar_ratio(rars,portfolio,ratio_name):
|
511
|
+
def draw_rar_ratio(rars,portfolio,ratio_name,pname):
|
463
512
|
"""
|
464
513
|
功能:绘制滚动窗口曲线
|
465
514
|
输入:滚动数据df,投资组合,指数名称
|
@@ -482,11 +531,13 @@ def draw_rar_ratio(rars,portfolio,ratio_name):
|
|
482
531
|
plt.plot(rars['RAR'],label=labeltxt,color='red',lw=1)
|
483
532
|
#plt.plot(rars['Mean(Ret)'],label='Stock(s) return(%)',color='blue',lw=1)
|
484
533
|
plt.axhline(y=0.0,color='black',linestyle=':')
|
485
|
-
|
534
|
+
"""
|
486
535
|
titletxt='风险调整收益的滚动趋势'+'\n'+str(ticker_name(stocklist))
|
487
536
|
if len(stocklist) > 1:
|
488
537
|
titletxt=titletxt+'\n持仓比例: '+str(portionlist)
|
489
538
|
"""
|
539
|
+
titletxt='风险调整收益的滚动趋势:'+pname
|
540
|
+
"""
|
490
541
|
if len(stocklist) == 1:
|
491
542
|
titletxt='风险调整收益的滚动趋势'+'\n('+ticker_name(stocklist)+')'
|
492
543
|
"""
|
siat/risk_adjusted_return2.py
CHANGED
@@ -1721,7 +1721,7 @@ if __name__=='__main__':
|
|
1721
1721
|
printout=True)
|
1722
1722
|
|
1723
1723
|
|
1724
|
-
def compare_rar_security(ticker,start,end,
|
1724
|
+
def compare_rar_security(ticker,start,end='today',indicator='sharpe', \
|
1725
1725
|
ret_type="Annual Adj Ret%", \
|
1726
1726
|
RF=0, \
|
1727
1727
|
regression_period=365, \
|
@@ -1741,6 +1741,8 @@ def compare_rar_security(ticker,start,end,rar='sharpe', \
|
|
1741
1741
|
|
1742
1742
|
注意:trailing=7,trend_threshhold=0.05,更加贴合视觉效果
|
1743
1743
|
"""
|
1744
|
+
start,end=start_end_preprocess(start,end)
|
1745
|
+
rar=indicator
|
1744
1746
|
|
1745
1747
|
#情形1:多个证券
|
1746
1748
|
if isinstance(ticker,list):
|
siat/risk_evaluation.py
CHANGED
@@ -186,7 +186,27 @@ def stock_VaR(ticker,shares,today,future_days=1,alpha=0.99, \
|
|
186
186
|
get_VaR_allmodels(ticker=ticker,shares=shares,today=today, \
|
187
187
|
future_days=future_days,alpha=alpha,pastyears=pastyears)
|
188
188
|
|
189
|
+
return
|
189
190
|
|
191
|
+
#==============================================================================
|
192
|
+
def security_VaR(ticker,shares,today,future_days=1,alpha=0.99, \
|
193
|
+
pastyears=1,printout=True,random=10000,mctype='random', \
|
194
|
+
model="normal_standard"):
|
195
|
+
"""
|
196
|
+
功能:持有证券的VaR,支持选择四种模型
|
197
|
+
输入参数:证券代码,持有股数,当前日期,未来持有时间(天),置信度,
|
198
|
+
使用历史数据的年数,是否打印结果,模型方法
|
199
|
+
模型方法:标准正态法normal_standard,修正正态法normal_modified,
|
200
|
+
蒙特卡洛模拟法montecarlo,历史排序模拟法historical
|
201
|
+
输出:VaR(负数金额,单位与股价的金额单位相同),VaR比率
|
202
|
+
说明:套壳函数stock_VaR
|
203
|
+
"""
|
204
|
+
stock_VaR(ticker=ticker,shares=shares,today=today,future_days=future_days,alpha=alpha, \
|
205
|
+
pastyears=pastyears,printout=printout,random=random,mctype=mctype, \
|
206
|
+
model=model)
|
207
|
+
|
208
|
+
return
|
209
|
+
|
190
210
|
#==============================================================================
|
191
211
|
if __name__ == '__main__':
|
192
212
|
ticker='BABA'
|
@@ -318,7 +338,7 @@ if __name__ == '__main__':
|
|
318
338
|
|
319
339
|
|
320
340
|
#==============================================================================
|
321
|
-
def compare_VaR(
|
341
|
+
def compare_VaR(ticker,shares,datelist, \
|
322
342
|
future_days=1,alpha=0.99,pastyears=1,model='normal_standard'):
|
323
343
|
"""
|
324
344
|
功能:比较多个日期持有一定天数股票资产的VaR高低
|
@@ -328,6 +348,8 @@ def compare_VaR(tickerlist,shares,datelist, \
|
|
328
348
|
输出:无
|
329
349
|
显示:折线图,各个资产的VaR金额和比率对比
|
330
350
|
"""
|
351
|
+
tickerlist=ticker
|
352
|
+
|
331
353
|
modellist=['normal_standard','normal_modified']
|
332
354
|
if not (model in modellist):
|
333
355
|
print(" #Error(compare_VaR): unsupported model",model)
|
@@ -378,7 +400,7 @@ def compare_VaR_normal_standard(tickerlist,shares,datelist, \
|
|
378
400
|
sys.stdout.close()
|
379
401
|
sys.stdout = self._original_stdout
|
380
402
|
|
381
|
-
print("
|
403
|
+
print(" The comparison may take time, please wait ...")
|
382
404
|
markerlist=['.','o','s','*','+','x','1','2']
|
383
405
|
for t in tickerlist:
|
384
406
|
pos=tickerlist.index(t)
|
@@ -497,6 +519,23 @@ def stock_ES(ticker,shares,today,future_days=1,alpha=0.99, \
|
|
497
519
|
pastyears=pastyears,printout=printout)
|
498
520
|
return ES,ratio
|
499
521
|
|
522
|
+
#==============================================================================
|
523
|
+
def security_ES(ticker,shares,today,future_days=1,alpha=0.99, \
|
524
|
+
pastyears=1,printout=True,random=10000,mctype='random', \
|
525
|
+
model="normal_standard"):
|
526
|
+
"""
|
527
|
+
功能:持有证券的预期不足ES,支持选择模型
|
528
|
+
输入参数:证券代码,持有股数,当前日期,未来持有时间(天),置信度,
|
529
|
+
使用历史数据的年数,是否打印结果,模型方法
|
530
|
+
模型方法:默认标准正态法normal_standard
|
531
|
+
说明:套壳函数stock_ES
|
532
|
+
"""
|
533
|
+
ES,ESratio=stock_ES(ticker=ticker,shares=shares,today=today,future_days=future_days,alpha=alpha, \
|
534
|
+
pastyears=pastyears,printout=printout,random=random,mctype=mctype, \
|
535
|
+
model=model)
|
536
|
+
|
537
|
+
return
|
538
|
+
|
500
539
|
#==============================================================================
|
501
540
|
if __name__ == '__main__':
|
502
541
|
ticker='JD'
|
@@ -618,7 +657,7 @@ if __name__ == '__main__':
|
|
618
657
|
result=series_ES_normal_standard('BABA',10000,datelist,1,0.99)
|
619
658
|
|
620
659
|
#==============================================================================
|
621
|
-
def compare_ES(
|
660
|
+
def compare_ES(ticker,shares,datelist, \
|
622
661
|
future_days=1,alpha=0.99,pastyears=1,model='normal_standard'):
|
623
662
|
"""
|
624
663
|
功能:比较多个日期持有一定天数股票资产的ES高低
|
@@ -628,6 +667,8 @@ def compare_ES(tickerlist,shares,datelist, \
|
|
628
667
|
输出:无
|
629
668
|
显示:折线图,各个资产的ES金额和比率对比
|
630
669
|
"""
|
670
|
+
tickerlist=ticker
|
671
|
+
|
631
672
|
modellist=['normal_standard']
|
632
673
|
if not (model in modellist):
|
633
674
|
print(" #Error(compare_ES): unsupported model",model)
|
@@ -659,7 +700,7 @@ def compare_ES_normal_standard(tickerlist,shares,datelist, \
|
|
659
700
|
sys.stdout.close()
|
660
701
|
sys.stdout = self._original_stdout
|
661
702
|
|
662
|
-
print("
|
703
|
+
print(" The comparison may take time, please wait ...")
|
663
704
|
markerlist=['.','o','s','*','+','x','1','2']
|
664
705
|
for t in tickerlist:
|
665
706
|
pos=tickerlist.index(t)
|
@@ -1001,7 +1042,7 @@ def compare_VaR_normal_modified(tickerlist,shares,datelist, \
|
|
1001
1042
|
sys.stdout.close()
|
1002
1043
|
sys.stdout = self._original_stdout
|
1003
1044
|
|
1004
|
-
print("
|
1045
|
+
print(" The comparison may take time, please wait ...")
|
1005
1046
|
markerlist=['.','o','s','*','+','x','1','2']
|
1006
1047
|
for t in tickerlist:
|
1007
1048
|
pos=tickerlist.index(t)
|
siat/sector_china.py
CHANGED
@@ -260,7 +260,8 @@ def sector_rank_sina(indicator="涨跌幅",category="新浪行业",rank=5):
|
|
260
260
|
df=sector_rank_china(comp=indicator,indicator=category,num=rank)
|
261
261
|
return df
|
262
262
|
|
263
|
-
def sector_rank_china(comp="涨跌幅",indicator="新浪行业",num=10):
|
263
|
+
#def sector_rank_china(comp="涨跌幅",indicator="新浪行业",num=10):
|
264
|
+
def sector_rank_china(ticker="新浪行业",indicator="涨跌幅",rank=10):
|
264
265
|
"""
|
265
266
|
功能:按照比较指标降序排列
|
266
267
|
comp="涨跌幅",平均价格,公司家数
|
@@ -269,6 +270,10 @@ def sector_rank_china(comp="涨跌幅",indicator="新浪行业",num=10):
|
|
269
270
|
|
270
271
|
注意:公司家数字段最大值为100,是bug?
|
271
272
|
"""
|
273
|
+
comp=indicator
|
274
|
+
indicator=ticker
|
275
|
+
num=rank
|
276
|
+
|
272
277
|
#检查选项是否支持
|
273
278
|
#complist=["涨跌幅","成交量","平均价格","公司家数"]
|
274
279
|
complist=["涨跌幅","平均价格","公司家数"]
|
@@ -421,12 +426,17 @@ def sector_detail_sina(sector="new_dlhy",indicator="涨跌幅",rank=5):
|
|
421
426
|
return df
|
422
427
|
|
423
428
|
|
424
|
-
def sector_detail_china(sector="new_dlhy",comp="涨跌幅",num=10):
|
429
|
+
#def sector_detail_china(sector="new_dlhy",comp="涨跌幅",num=10):
|
430
|
+
def sector_detail_china(ticker="new_dlhy",indicator="涨跌幅",rank=10):
|
425
431
|
"""
|
426
432
|
功能:按照板块内部股票的比较指标降序排列
|
427
433
|
sector:板块代码
|
428
434
|
num:为正数时列出最高的前几名,为负数时列出最后几名
|
429
435
|
"""
|
436
|
+
sector=ticker
|
437
|
+
comp=indicator
|
438
|
+
num=rank
|
439
|
+
|
430
440
|
debug=False
|
431
441
|
|
432
442
|
#检查选项是否支持
|