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,867 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
"""
|
3
|
-
本模块功能:投资组合的VaR(在险价值)和ES(预期损失)分析
|
4
|
-
所属工具包:证券投资分析工具SIAT
|
5
|
-
SIAT:Security Investment Analysis Tool
|
6
|
-
创建日期:2018年6月16日
|
7
|
-
最新修订日期:2020年7月23日
|
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
|
-
#统一设定绘制的图片大小:数值为英寸,1英寸=100像素
|
43
|
-
#plt.rcParams['figure.figsize']=(12.8,7.2)
|
44
|
-
plt.rcParams['figure.figsize']=(12.8,6.4)
|
45
|
-
plt.rcParams['figure.dpi']=300
|
46
|
-
plt.rcParams['font.size'] = 13
|
47
|
-
plt.rcParams['xtick.labelsize']=11 #横轴字体大小
|
48
|
-
plt.rcParams['ytick.labelsize']=11 #纵轴字体大小
|
49
|
-
|
50
|
-
title_txt_size=16
|
51
|
-
ylabel_txt_size=14
|
52
|
-
xlabel_txt_size=14
|
53
|
-
legend_txt_size=14
|
54
|
-
|
55
|
-
#设置绘图风格:网格虚线
|
56
|
-
plt.rcParams['axes.grid']=True
|
57
|
-
#plt.rcParams['grid.color']='steelblue'
|
58
|
-
#plt.rcParams['grid.linestyle']='dashed'
|
59
|
-
#plt.rcParams['grid.linewidth']=0.5
|
60
|
-
#plt.rcParams['axes.facecolor']='whitesmoke'
|
61
|
-
|
62
|
-
#==============================================================================
|
63
|
-
import os, sys
|
64
|
-
class HiddenPrints:
|
65
|
-
def __enter__(self):
|
66
|
-
self._original_stdout = sys.stdout
|
67
|
-
sys.stdout = open(os.devnull, 'w')
|
68
|
-
|
69
|
-
def __exit__(self, exc_type, exc_val, exc_tb):
|
70
|
-
sys.stdout.close()
|
71
|
-
sys.stdout = self._original_stdout
|
72
|
-
#==============================================================================
|
73
|
-
|
74
|
-
#==============================================================================
|
75
|
-
if __name__ == '__main__':
|
76
|
-
portfolio={'Market':('China','000001.SS'),'300782.SZ':1}
|
77
|
-
fromdate='2022-1-1'
|
78
|
-
todate='2022-4-18'
|
79
|
-
|
80
|
-
def get_portfolio_prices0(portfolio,fromdate,todate):
|
81
|
-
"""
|
82
|
-
功能:抓取投资组合portfolio的每日价值
|
83
|
-
输入:投资组合portfolio,开始日期,结束日期
|
84
|
-
fromdate: 样本开始日期。格式:'YYYY-MM-DD'
|
85
|
-
todate: 样本结束日期。既可以是今天日期,也可以是一个历史日期
|
86
|
-
|
87
|
-
输出:投资组合的价格序列,按照日期升序排列
|
88
|
-
"""
|
89
|
-
|
90
|
-
#解构投资组合
|
91
|
-
_,mktidx,tickerlist,sharelist,ticker_type=decompose_portfolio(portfolio)
|
92
|
-
|
93
|
-
#检查股票列表个数与份额列表个数是否一致
|
94
|
-
if len(tickerlist) != len(sharelist):
|
95
|
-
print("#Error(get_portfolio_prices0): numbers of stocks and shares mismatch.")
|
96
|
-
return None
|
97
|
-
|
98
|
-
#抓取股票价格
|
99
|
-
p=get_prices(tickerlist,fromdate,todate)
|
100
|
-
if p is None: return None
|
101
|
-
|
102
|
-
import pandas as pd
|
103
|
-
#计算投资组合的开盘价
|
104
|
-
op=p[['Open']]
|
105
|
-
#计算投资组合的价值
|
106
|
-
oprice=pd.DataFrame(op.dot(sharelist))
|
107
|
-
oprice.rename(columns={0: 'Open'}, inplace=True)
|
108
|
-
|
109
|
-
#计算投资组合的收盘价
|
110
|
-
cp=p[['Close']]
|
111
|
-
#计算投资组合的价值
|
112
|
-
cprice=pd.DataFrame(cp.dot(sharelist))
|
113
|
-
cprice.rename(columns={0: 'Close'}, inplace=True)
|
114
|
-
|
115
|
-
#计算投资组合的调整收盘价
|
116
|
-
acp=p[['Adj Close']]
|
117
|
-
#计算投资组合的价值
|
118
|
-
acprice=pd.DataFrame(acp.dot(sharelist))
|
119
|
-
acprice.rename(columns={0: 'Adj Close'}, inplace=True)
|
120
|
-
|
121
|
-
#计算投资组合的交易量
|
122
|
-
vol=p[['Volume']]
|
123
|
-
#计算投资组合的价值
|
124
|
-
pfvol=pd.DataFrame(vol.dot(sharelist))
|
125
|
-
pfvol.rename(columns={0: 'Volume'}, inplace=True)
|
126
|
-
|
127
|
-
#计算投资组合的交易金额
|
128
|
-
if len(tickerlist)==1:
|
129
|
-
p['Amount']=p['Close']*p['Volume']
|
130
|
-
else:
|
131
|
-
for t in tickerlist:
|
132
|
-
p['Amount',t]=p['Close',t]*p['Volume',t]
|
133
|
-
amt=p[['Amount']]
|
134
|
-
#计算投资组合的价值
|
135
|
-
pfamt=pd.DataFrame(amt.dot(sharelist))
|
136
|
-
pfamt.rename(columns={0: 'Amount'}, inplace=True)
|
137
|
-
|
138
|
-
#合成开盘价、收盘价、调整收盘价、交易量和交易金额
|
139
|
-
pf1=pd.merge(oprice,cprice,how='inner',left_index=True,right_index=True)
|
140
|
-
pf2=pd.merge(pf1,acprice,how='inner',left_index=True,right_index=True)
|
141
|
-
pf3=pd.merge(pf2,pfvol,how='inner',left_index=True,right_index=True)
|
142
|
-
pf4=pd.merge(pf3,pfamt,how='inner',left_index=True,right_index=True)
|
143
|
-
pf4['Ret']=pf4['Close'].pct_change()
|
144
|
-
|
145
|
-
#获得期间的市场收益率:假设无风险收益率非常小,可以忽略
|
146
|
-
m=get_prices(mktidx,fromdate,todate)
|
147
|
-
m['Mkt']=m['Close'].pct_change()
|
148
|
-
rf_df=m[['Mkt']]
|
149
|
-
|
150
|
-
#合并pf4与rf_df
|
151
|
-
prices=pd.merge(pf4,rf_df,how='left',left_index=True,right_index=True)
|
152
|
-
|
153
|
-
#提取日期和星期几
|
154
|
-
prices['Date']=prices.index.strftime("%Y-%m-%d")
|
155
|
-
prices['Weekday']=prices.index.weekday+1
|
156
|
-
|
157
|
-
prices['Portfolio']=str(tickerlist)
|
158
|
-
prices['Shares']=str(sharelist)
|
159
|
-
prices['Adjustment']=prices.apply(lambda x: \
|
160
|
-
False if x['Close']==x['Adj Close'] else True, axis=1)
|
161
|
-
|
162
|
-
pfdf=prices[['Portfolio','Shares','Date','Weekday', \
|
163
|
-
'Open','Close','Adj Close','Adjustment', \
|
164
|
-
'Volume','Amount','Ret','Mkt']]
|
165
|
-
|
166
|
-
#判断空值,控制空值可能引起的程序崩溃
|
167
|
-
if pfdf is None:
|
168
|
-
print("#Error(get_portfolio_prices0): failed to retrieve portfolio data")
|
169
|
-
return None
|
170
|
-
pfdf.dropna(inplace=True)
|
171
|
-
if (pfdf is None) or (len(pfdf)==0):
|
172
|
-
print("#Error(get_portfolio_prices0): failed to retrieve portfolio data")
|
173
|
-
return None
|
174
|
-
|
175
|
-
return pfdf
|
176
|
-
|
177
|
-
|
178
|
-
#==============================================================================
|
179
|
-
def calc_VaR_normal_standard(ret_series,future_days=1,alpha=0.99):
|
180
|
-
|
181
|
-
"""
|
182
|
-
功能:VaR算法之标准正态法
|
183
|
-
输入参数:收益率序列(非百分比),未来持有时间(天),置信度
|
184
|
-
输出参数:VaR比率,正数
|
185
|
-
"""
|
186
|
-
#去掉空值
|
187
|
-
r=ret_series[~ret_series.isnull()]
|
188
|
-
|
189
|
-
import numpy as np
|
190
|
-
from scipy import stats
|
191
|
-
|
192
|
-
z=stats.norm.ppf(1-alpha)
|
193
|
-
|
194
|
-
miu_daily=np.mean(r)
|
195
|
-
miu_days=np.power(miu_daily+1,future_days)-1
|
196
|
-
|
197
|
-
sigma_daily=np.std(r)
|
198
|
-
sigma_days=np.sqrt(future_days)*sigma_daily
|
199
|
-
|
200
|
-
VaR_ratio=abs(miu_days+z*sigma_days)
|
201
|
-
|
202
|
-
return VaR_ratio
|
203
|
-
|
204
|
-
#==============================================================================
|
205
|
-
def calc_ES_normal_standard(ret_series,future_days=1,alpha=0.99):
|
206
|
-
"""
|
207
|
-
功能:计算ES,标准正态法
|
208
|
-
输入参数:收益率序列,未来持有日期,置信度
|
209
|
-
输出:ES比率,正数
|
210
|
-
"""
|
211
|
-
#去掉空值
|
212
|
-
r=ret_series[~ret_series.isnull()]
|
213
|
-
|
214
|
-
import numpy as np
|
215
|
-
from scipy import stats
|
216
|
-
|
217
|
-
z=stats.norm.ppf(1-alpha)
|
218
|
-
miu_daily=np.mean(r)
|
219
|
-
miu_days=np.power(miu_daily+1,future_days)-1
|
220
|
-
|
221
|
-
sigma_daily=np.std(r)
|
222
|
-
sigma_days=np.sqrt(future_days)*sigma_daily
|
223
|
-
|
224
|
-
zES=-stats.norm.pdf(z)/(1-alpha)
|
225
|
-
ratio=abs(miu_days+zES*sigma_days)
|
226
|
-
|
227
|
-
return ratio
|
228
|
-
|
229
|
-
#==============================================================================
|
230
|
-
def calc_VaR_normal_modified(ret_series,future_days=1,alpha=0.99):
|
231
|
-
"""
|
232
|
-
功能:VaR算法之修正正态法
|
233
|
-
#输入参数:日收益率序列(非百分比),未来持有日期,置信度
|
234
|
-
#输出参数:VaR比率,正数
|
235
|
-
"""
|
236
|
-
#去掉空值
|
237
|
-
r=ret_series[~ret_series.isnull()]
|
238
|
-
|
239
|
-
from scipy import stats
|
240
|
-
import numpy as np
|
241
|
-
|
242
|
-
z=np.abs(stats.norm.ppf(1-alpha))
|
243
|
-
S=stats.skew(r)
|
244
|
-
K=stats.kurtosis(r)
|
245
|
-
|
246
|
-
t1=1/6*(np.power(z,2)-1)*S
|
247
|
-
t2=1/24*(np.power(z,3)-3*z)*K
|
248
|
-
t3=1/36*(2*np.power(z,3)-5*z)*np.power(S,2)
|
249
|
-
t=z+t1+t2-t3
|
250
|
-
|
251
|
-
miu_daily=np.mean(r)
|
252
|
-
miu_days=np.power(miu_daily+1,future_days)-1
|
253
|
-
sigma_daily=np.std(r)
|
254
|
-
sigma_days=np.sqrt(future_days)*sigma_daily
|
255
|
-
|
256
|
-
ratio=abs(miu_days+t*sigma_days)
|
257
|
-
|
258
|
-
return ratio
|
259
|
-
|
260
|
-
#==============================================================================
|
261
|
-
def calc_ES_normal_modified(ret_series,future_days=1,alpha=0.99):
|
262
|
-
"""
|
263
|
-
功能:ES算法之修正正态法
|
264
|
-
#输入参数:日收益率序列(非百分比),未来持有日期,置信度
|
265
|
-
#输出参数:ES比率,正数
|
266
|
-
"""
|
267
|
-
#去掉空值
|
268
|
-
r=ret_series[~ret_series.isnull()]
|
269
|
-
|
270
|
-
from scipy import stats
|
271
|
-
import numpy as np
|
272
|
-
|
273
|
-
#计算替代z的t值
|
274
|
-
z=np.abs(stats.norm.ppf(1-alpha))
|
275
|
-
S=stats.skew(r)
|
276
|
-
K=stats.kurtosis(r)
|
277
|
-
|
278
|
-
t1=1/6*(np.power(z,2)-1)*S
|
279
|
-
t2=1/24*(np.power(z,3)-3*z)*K
|
280
|
-
t3=1/36*(2*np.power(z,3)-5*z)*np.power(S,2)
|
281
|
-
t=z+t1+t2-t3
|
282
|
-
|
283
|
-
miu_daily=np.mean(r)
|
284
|
-
miu_days=np.power(miu_daily+1,future_days)-1
|
285
|
-
sigma_daily=np.std(r)
|
286
|
-
sigma_days=np.sqrt(future_days)*sigma_daily
|
287
|
-
|
288
|
-
#使用t替代原来的z
|
289
|
-
zES=-stats.norm.pdf(t)/(1-alpha)
|
290
|
-
ratio=abs(miu_days+zES*sigma_days)
|
291
|
-
|
292
|
-
return ratio
|
293
|
-
|
294
|
-
#==============================================================================
|
295
|
-
def get_grouped_rets(ret_series,groupsize=1):
|
296
|
-
"""
|
297
|
-
功能:给定收益率序列pfdf,按照组的大小,在pfdf内创建滚动分组,
|
298
|
-
计算每组组内的累计收益率,消除空值,返回组收益率序列
|
299
|
-
"""
|
300
|
-
#测试用数据,测试后应注释掉
|
301
|
-
"""
|
302
|
-
portfolio={'Market':('US','^GSPC'),'AAPL':0.5,'MSFT':0.3,'IBM':0.2}
|
303
|
-
fromdate='2019-7-31'
|
304
|
-
todate ='2019-8-31'
|
305
|
-
groupsize=2
|
306
|
-
#获得投资组合的收益率
|
307
|
-
pfdf=get_portfolio_prices0(portfolio,fromdate,todate)
|
308
|
-
import pandas as pd
|
309
|
-
ret_series=pd.Series(pfdf['Ret'])
|
310
|
-
"""
|
311
|
-
|
312
|
-
#定义组内累计收益率计算方法
|
313
|
-
cumret=lambda x:(x+1.0).prod()-1.0
|
314
|
-
#使用滚动窗口分组,计算各组收益率gret
|
315
|
-
gret_series=ret_series.rolling(groupsize).apply(cumret)
|
316
|
-
gret_series=gret_series[~gret_series.isnull()]
|
317
|
-
|
318
|
-
#返回组收益率序列
|
319
|
-
return gret_series
|
320
|
-
|
321
|
-
#==============================================================================
|
322
|
-
def calc_VaR_historical(ret_series,future_days=1,alpha=0.99):
|
323
|
-
"""
|
324
|
-
功能:VaR算法之历史模拟法
|
325
|
-
输入参数:历史日收益率序列,未来持有日期,置信度
|
326
|
-
输出:VaR比率,正数
|
327
|
-
"""
|
328
|
-
#去掉空值
|
329
|
-
r0=ret_series[~ret_series.isnull()]
|
330
|
-
#按未来持有期间数计算分组收益率
|
331
|
-
r=get_grouped_rets(r0,future_days)
|
332
|
-
|
333
|
-
import numpy as np
|
334
|
-
n=len(r)
|
335
|
-
t=int(n*(1-alpha))
|
336
|
-
SR=np.sort(r)
|
337
|
-
|
338
|
-
if t>=1:
|
339
|
-
A=SR[t-1] #SR的第一个元素的序号是0
|
340
|
-
else:
|
341
|
-
A=SR[0]
|
342
|
-
|
343
|
-
VaR_ratio=abs(A)
|
344
|
-
|
345
|
-
return VaR_ratio
|
346
|
-
|
347
|
-
#==============================================================================
|
348
|
-
def calc_ES_historical(ret_series,future_days=1,alpha=0.99):
|
349
|
-
"""
|
350
|
-
功能:ES算法之历史模拟法
|
351
|
-
输入参数:历史日收益率序列,未来持有日期,置信度
|
352
|
-
输出:ES比率,正数
|
353
|
-
要求:足够多的历史数据
|
354
|
-
"""
|
355
|
-
#去掉空值
|
356
|
-
r0=ret_series[~ret_series.isnull()]
|
357
|
-
#按未来持有期间数计算分组收益率
|
358
|
-
r=get_grouped_rets(r0,future_days)
|
359
|
-
|
360
|
-
import numpy as np
|
361
|
-
n=len(r)
|
362
|
-
t=int(n*(1-alpha))
|
363
|
-
SR=np.sort(r)
|
364
|
-
|
365
|
-
if t>2:
|
366
|
-
#SR中第t个元素是VaR,第0~(t-1)个元素的均值是ES
|
367
|
-
#SR的第一个元素的序号是0
|
368
|
-
A=np.mean(SR[0:(t-2)])
|
369
|
-
else:
|
370
|
-
A=SR[0]
|
371
|
-
|
372
|
-
ratio=abs(A)
|
373
|
-
|
374
|
-
return ratio
|
375
|
-
|
376
|
-
if __name__ == '__main__':
|
377
|
-
Market={'Market':('China','000001.SS')}
|
378
|
-
Stocks={'300782.SZ':2,'300661.SZ':3,'688019.SS':4}
|
379
|
-
portfolio=dict(Market,**Stocks)
|
380
|
-
prices=get_portfolio_prices0(portfolio,'2019-7-20','2020-7-20')
|
381
|
-
ret_series=prices['Ret']
|
382
|
-
future_days=3
|
383
|
-
alpha=0.99
|
384
|
-
|
385
|
-
#==============================================================================
|
386
|
-
def calc_VaR_montecarlo(ret_series,future_days=1,alpha=0.99, \
|
387
|
-
random=10000,mctype='random'):
|
388
|
-
"""
|
389
|
-
功能:VaR算法之蒙特卡洛模拟法,持有多日
|
390
|
-
输入参数:历史日收益率序列,未来持有天数,置信度,重复模拟次数,模拟类型
|
391
|
-
注:重复模拟次数越多,准确率就越高,但耗时也越多
|
392
|
-
输出:持有多天的VaR(金额)
|
393
|
-
"""
|
394
|
-
#去掉空值
|
395
|
-
r=ret_series[~ret_series.isnull()]
|
396
|
-
|
397
|
-
import pandas as pd
|
398
|
-
import numpy as np
|
399
|
-
#蒙特卡洛模拟类型:随机数or超采样
|
400
|
-
if mctype=='random': #随机数产生新的序列
|
401
|
-
#取得历史日收益率的均值和标准差
|
402
|
-
miu=np.mean(r)
|
403
|
-
sigma=np.std(r)
|
404
|
-
|
405
|
-
#指定随机数种子
|
406
|
-
np.random.seed(12345)
|
407
|
-
#按照历史日收益率的均值和标准差重复模拟一定次数,生成新的日收益率序列
|
408
|
-
RR=pd.Series(np.random.normal(miu,sigma,random))
|
409
|
-
else: #超采样产生新的序列
|
410
|
-
#将收益率序列转变为df
|
411
|
-
r1=pd.DataFrame(r)
|
412
|
-
r2=r1.sample(n=random,replace=True)
|
413
|
-
r2.sort_index(inplace=True)
|
414
|
-
RR=pd.Series(r2.iloc[:,0])
|
415
|
-
"""
|
416
|
-
r1=np.random.choice(r,size=random,replace=True)
|
417
|
-
RR=pd.Series(r1)
|
418
|
-
"""
|
419
|
-
|
420
|
-
#基于新的日收益率序列,使用标准正态法计算VaR
|
421
|
-
ratio=calc_VaR_normal_standard(RR,future_days,alpha)
|
422
|
-
#ratio=calc_VaR_historical(RR,future_days,alpha)
|
423
|
-
|
424
|
-
return ratio
|
425
|
-
|
426
|
-
if __name__ == '__main__':
|
427
|
-
random=1000
|
428
|
-
mctype='oversampling'
|
429
|
-
|
430
|
-
#==============================================================================
|
431
|
-
def calc_ES_montecarlo(ret_series,future_days=1,alpha=0.99, \
|
432
|
-
random=10000,mctype='random'):
|
433
|
-
"""
|
434
|
-
功能:ES算法之蒙特卡洛模拟法,持有多日
|
435
|
-
输入参数:历史日收益率序列,未来持有天数,置信度,重复模拟次数,模拟类型
|
436
|
-
注:重复模拟次数越多,准确率就越高,但耗时也越多
|
437
|
-
输出:持有多天的ES比率
|
438
|
-
"""
|
439
|
-
#去掉空值
|
440
|
-
r=ret_series[~ret_series.isnull()]
|
441
|
-
|
442
|
-
import pandas as pd
|
443
|
-
import numpy as np
|
444
|
-
#蒙特卡洛模拟类型:随机数or超采样
|
445
|
-
if mctype=='random': #随机数产生新的序列
|
446
|
-
#取得历史日收益率的均值和标准差
|
447
|
-
miu=np.mean(r)
|
448
|
-
sigma=np.std(r)
|
449
|
-
|
450
|
-
#指定随机数种子
|
451
|
-
np.random.seed(12345)
|
452
|
-
#按照历史日收益率的均值和标准差重复模拟一定次数,生成新的日收益率序列
|
453
|
-
RR=pd.Series(np.random.normal(miu,sigma,random))
|
454
|
-
else: #超采样产生新的序列
|
455
|
-
#将收益率序列转变为df
|
456
|
-
r1=pd.DataFrame(r)
|
457
|
-
r2=r1.sample(n=random,replace=True)
|
458
|
-
r2.sort_index(inplace=True)
|
459
|
-
RR=pd.Series(r2.iloc[:,0])
|
460
|
-
"""
|
461
|
-
r1=np.random.choice(r,size=random,replace=True)
|
462
|
-
RR=pd.Series(r1)
|
463
|
-
"""
|
464
|
-
|
465
|
-
#基于新的日收益率序列,使用标准正态法计算ES
|
466
|
-
ratio=calc_ES_normal_standard(RR,future_days,alpha)
|
467
|
-
|
468
|
-
return ratio
|
469
|
-
|
470
|
-
#==============================================================================
|
471
|
-
if __name__ == '__main__':
|
472
|
-
portfolio={'Market':('China','000001.SS'),'000661.SZ':2,'603392.SS':3,'300601.SZ':4}
|
473
|
-
today='2020-7-20'
|
474
|
-
future_days=1
|
475
|
-
alpha=0.99
|
476
|
-
pastyears=1
|
477
|
-
model='all'
|
478
|
-
printout=True
|
479
|
-
|
480
|
-
|
481
|
-
def get_VaR_portfolio(portfolio,today,future_days=1,alpha=0.99, \
|
482
|
-
pastyears=1,model='normal_standard',printout=True):
|
483
|
-
"""
|
484
|
-
功能:基于指定模型model,计算投资组合portfolio的VaR金额和比率
|
485
|
-
"""
|
486
|
-
print(" Start working on portfolio VaR, please wait ...")
|
487
|
-
|
488
|
-
#检查model类型
|
489
|
-
modellist=['normal_standard','normal_modified','historical','montecarlo', \
|
490
|
-
'mc_oversampling','all']
|
491
|
-
modeltyp=model.lower()
|
492
|
-
if modeltyp not in modellist:
|
493
|
-
print(" #Error(get_VaR_portfolio): Unsupported type of model,",model)
|
494
|
-
print(" Supported models:",modellist)
|
495
|
-
return None,None
|
496
|
-
|
497
|
-
#获得样本起始日期
|
498
|
-
start=get_start_date(today,pastyears)
|
499
|
-
if start is None: return None,None
|
500
|
-
|
501
|
-
#抓取投资组合股价和收益率
|
502
|
-
print(" Searching for portfolio prices from",start,'to',today)
|
503
|
-
prices=get_portfolio_prices0(portfolio,start,today)
|
504
|
-
#判断空值,控制空值可能引起的程序崩溃
|
505
|
-
if prices is None:
|
506
|
-
print(" #Error(get_VaR_portfolio): failed to retrieve portfolio prices")
|
507
|
-
return None,None
|
508
|
-
|
509
|
-
prices.dropna(inplace=True)
|
510
|
-
if len(prices)==0:
|
511
|
-
print(" #Error(get_VaR_portfolio): zero records found for the portfolio")
|
512
|
-
return None,None
|
513
|
-
|
514
|
-
num=len(prices)
|
515
|
-
ret_series=prices['Ret']
|
516
|
-
|
517
|
-
print(" Calculating portfolio VaR ...")
|
518
|
-
#计算当日头寸
|
519
|
-
position=round(prices['Close'][-1],2)
|
520
|
-
VaRlist=[]; ratiolist=[]
|
521
|
-
#标准正态法
|
522
|
-
if modeltyp in ['normal_standard','all']:
|
523
|
-
ratio=calc_VaR_normal_standard(ret_series,future_days,alpha)
|
524
|
-
VaR=-round(position*ratio,2)
|
525
|
-
VaRlist=VaRlist+[VaR]
|
526
|
-
VaR_ratio=round(ratio,4)
|
527
|
-
ratiolist=ratiolist+[VaR_ratio]
|
528
|
-
|
529
|
-
#修正正态法
|
530
|
-
if modeltyp in ['normal_modified','all']:
|
531
|
-
ratio=calc_VaR_normal_modified(ret_series,future_days,alpha)
|
532
|
-
VaR=-round(position*ratio,2)
|
533
|
-
VaRlist=VaRlist+[VaR]
|
534
|
-
VaR_ratio=round(ratio,4)
|
535
|
-
ratiolist=ratiolist+[VaR_ratio]
|
536
|
-
|
537
|
-
#历史模拟法
|
538
|
-
if modeltyp in ['historical','all']:
|
539
|
-
ratio=calc_VaR_historical(ret_series,future_days,alpha)
|
540
|
-
VaR=-round(position*ratio,2)
|
541
|
-
VaRlist=VaRlist+[VaR]
|
542
|
-
VaR_ratio=round(ratio,4)
|
543
|
-
ratiolist=ratiolist+[VaR_ratio]
|
544
|
-
|
545
|
-
#蒙特卡洛模拟法,随机数,默认
|
546
|
-
if modeltyp in ['montecarlo','all']:
|
547
|
-
ratio=calc_VaR_montecarlo(ret_series,future_days,alpha,mctype='random')
|
548
|
-
VaR=-round(position*ratio,2)
|
549
|
-
VaRlist=VaRlist+[VaR]
|
550
|
-
VaR_ratio=round(ratio,4)
|
551
|
-
ratiolist=ratiolist+[VaR_ratio]
|
552
|
-
|
553
|
-
#蒙特卡洛模拟法,超采样
|
554
|
-
if modeltyp in ['mc_oversampling','all']:
|
555
|
-
ratio=calc_VaR_montecarlo(ret_series,future_days,alpha, \
|
556
|
-
mctype='mc_oversampling')
|
557
|
-
VaR=-round(position*ratio,2)
|
558
|
-
VaRlist=VaRlist+[VaR]
|
559
|
-
VaR_ratio=round(ratio,4)
|
560
|
-
ratiolist=ratiolist+[VaR_ratio]
|
561
|
-
|
562
|
-
if not printout: return VaRlist,ratiolist
|
563
|
-
|
564
|
-
#输出VaR金额和比率
|
565
|
-
print("\n===== 在险价值VaR:投资组合 =====")
|
566
|
-
#_,_,tickerlist,sharelist,ticker_type=decompose_portfolio(portfolio)
|
567
|
-
#print("成分股列表 :",tickerlist)
|
568
|
-
#print("成分股的配置:",sharelist)
|
569
|
-
print("投资组合:",portfolio_name(portfolio))
|
570
|
-
print("当前日期:",today)
|
571
|
-
print("当前头寸(1份投资组合):",format(position,','))
|
572
|
-
print("预计持有天数:",future_days)
|
573
|
-
print("置信度水平:",str(int(alpha*100))+'%')
|
574
|
-
print("历史样本年数:",pastyears)
|
575
|
-
print("样本数量:",num)
|
576
|
-
|
577
|
-
import datetime as dt; today=dt.date.today()
|
578
|
-
footnote="\n数据来源:新浪/stooq,"+str(today)
|
579
|
-
if not (modeltyp == 'all'):
|
580
|
-
print("使用的模型:",model)
|
581
|
-
print("VaR金额/比率:",format(VaR,','), \
|
582
|
-
'\b,',str(round(VaR_ratio*100,2))+'%')
|
583
|
-
|
584
|
-
print(footnote)
|
585
|
-
return VaR,VaR_ratio
|
586
|
-
|
587
|
-
print("\n*** VaR金额/比率 ***")
|
588
|
-
modellist.pop()
|
589
|
-
for m in modellist:
|
590
|
-
pos=modellist.index(m)
|
591
|
-
v=VaRlist[pos]
|
592
|
-
r=ratiolist[pos]
|
593
|
-
print(" ",format(v,','),'\b,', \
|
594
|
-
str(round(r*100,2))+'%'+' ('+m+')')
|
595
|
-
|
596
|
-
print(footnote)
|
597
|
-
|
598
|
-
return VaRlist,ratiolist
|
599
|
-
|
600
|
-
if __name__ == '__main__':
|
601
|
-
portfolio={'Market':('China','000001.SS'),'000661.SZ':1,'603392.SS':2, \
|
602
|
-
'300601.SZ':3}
|
603
|
-
today='2020-7-20'
|
604
|
-
future_days=1
|
605
|
-
alpha=0.99
|
606
|
-
pastyears=1
|
607
|
-
model='all'
|
608
|
-
printout=True
|
609
|
-
|
610
|
-
#==============================================================================
|
611
|
-
def get_ES_portfolio(portfolio,today,future_days=1,alpha=0.99, \
|
612
|
-
pastyears=1,model='normal_standard',printout=True):
|
613
|
-
"""
|
614
|
-
功能:基于指定模型model,计算投资组合portfolio的ES金额和比率
|
615
|
-
"""
|
616
|
-
|
617
|
-
#检查model类型
|
618
|
-
modellist=['normal_standard','normal_modified','historical','montecarlo', \
|
619
|
-
'mc_oversampling','all']
|
620
|
-
modeltyp=model.lower()
|
621
|
-
if modeltyp not in modellist:
|
622
|
-
print("#Error(get_ES_portfolio): Unsupported type of model,",model)
|
623
|
-
print("Supported models:",modellist)
|
624
|
-
return None,None
|
625
|
-
|
626
|
-
#获得样本起始日期
|
627
|
-
start=get_start_date(today,pastyears)
|
628
|
-
if start is None: return None,None
|
629
|
-
#抓取投资组合股价和收益率
|
630
|
-
prices=get_portfolio_prices0(portfolio,start,today)
|
631
|
-
#判断空值,控制空值可能引起的程序崩溃
|
632
|
-
if prices is None:
|
633
|
-
print("#Error(get_ES_portfolio): failed to retrieve portfolio prices")
|
634
|
-
return None,None
|
635
|
-
prices.dropna(inplace=True)
|
636
|
-
if (prices is None) or (len(prices)==0):
|
637
|
-
print("#Error(get_ES_portfolio): failed to retrieve portfolio prices")
|
638
|
-
return None,None
|
639
|
-
|
640
|
-
num=len(prices)
|
641
|
-
ret_series=prices['Ret']
|
642
|
-
|
643
|
-
#计算当日头寸
|
644
|
-
position=round(prices['Close'][-1],2)
|
645
|
-
ESlist=[]; ratiolist=[]
|
646
|
-
#标准正态法
|
647
|
-
if modeltyp in ['normal_standard','all']:
|
648
|
-
ratio=calc_ES_normal_standard(ret_series,future_days,alpha)
|
649
|
-
ES=-round(position*ratio,2)
|
650
|
-
ESlist=ESlist+[ES]
|
651
|
-
ES_ratio=round(ratio,4)
|
652
|
-
ratiolist=ratiolist+[ES_ratio]
|
653
|
-
|
654
|
-
#修正正态法
|
655
|
-
if modeltyp in ['normal_modified','all']:
|
656
|
-
ratio=calc_ES_normal_modified(ret_series,future_days,alpha)
|
657
|
-
ES=-round(position*ratio,2)
|
658
|
-
ESlist=ESlist+[ES]
|
659
|
-
ES_ratio=round(ratio,4)
|
660
|
-
ratiolist=ratiolist+[ES_ratio]
|
661
|
-
|
662
|
-
#历史模拟法
|
663
|
-
if modeltyp in ['historical','all']:
|
664
|
-
ratio=calc_ES_historical(ret_series,future_days,alpha)
|
665
|
-
ES=-round(position*ratio,2)
|
666
|
-
ESlist=ESlist+[ES]
|
667
|
-
ES_ratio=round(ratio,4)
|
668
|
-
ratiolist=ratiolist+[ES_ratio]
|
669
|
-
|
670
|
-
#蒙特卡洛模拟法,随机数,默认
|
671
|
-
if modeltyp in ['montecarlo','all']:
|
672
|
-
ratio=calc_ES_montecarlo(ret_series,future_days,alpha,mctype='random')
|
673
|
-
ES=-round(position*ratio,2)
|
674
|
-
ESlist=ESlist+[ES]
|
675
|
-
ES_ratio=round(ratio,4)
|
676
|
-
ratiolist=ratiolist+[ES_ratio]
|
677
|
-
|
678
|
-
#蒙特卡洛模拟法,超采样
|
679
|
-
if modeltyp in ['mc_oversampling','all']:
|
680
|
-
ratio=calc_ES_montecarlo(ret_series,future_days,alpha, \
|
681
|
-
mctype='mc_oversampling')
|
682
|
-
ES=-round(position*ratio,2)
|
683
|
-
ESlist=ESlist+[ES]
|
684
|
-
ES_ratio=round(ratio,4)
|
685
|
-
ratiolist=ratiolist+[ES_ratio]
|
686
|
-
|
687
|
-
if not printout: return ESlist,ratiolist
|
688
|
-
|
689
|
-
#输出ES金额和比率
|
690
|
-
print("\n===== 投资组合的预期不足ES =====")
|
691
|
-
#_,_,tickerlist,sharelist,ticker_type=decompose_portfolio(portfolio)
|
692
|
-
#print("成分股列表 :",tickerlist)
|
693
|
-
#print("成分股配置 :",sharelist)
|
694
|
-
print("投资组合:",portfolio_name(portfolio))
|
695
|
-
print("当前日期:",today)
|
696
|
-
print("当前头寸(1份投资组合):",format(position,','))
|
697
|
-
print("预计持有天数:",future_days)
|
698
|
-
print("置信度水平:",str(int(alpha*100))+'%')
|
699
|
-
print("历史样本年数:",pastyears)
|
700
|
-
print("样本个数:",num)
|
701
|
-
|
702
|
-
import datetime as dt; today=dt.date.today()
|
703
|
-
footnote="\n数据来源:新浪/stooq,"+str(today)
|
704
|
-
|
705
|
-
if not (modeltyp == 'all'):
|
706
|
-
print("使用的模型:",model)
|
707
|
-
print("ES金额/比率:",format(ES,','), \
|
708
|
-
'\b,',str(round(ES_ratio*100,2))+'%')
|
709
|
-
print(footnote)
|
710
|
-
return ES,ES_ratio
|
711
|
-
|
712
|
-
print("ES金额/比率:")
|
713
|
-
modellist.pop()
|
714
|
-
for m in modellist:
|
715
|
-
pos=modellist.index(m)
|
716
|
-
v=ESlist[pos]
|
717
|
-
r=ratiolist[pos]
|
718
|
-
print(" ",format(v,','),'\b,', \
|
719
|
-
str(round(r*100,2))+'%'+' ('+m+')')
|
720
|
-
|
721
|
-
print(footnote)
|
722
|
-
|
723
|
-
return ESlist,ratiolist
|
724
|
-
|
725
|
-
if __name__ == '__main__':
|
726
|
-
portfolio={'Market':('China','000001.SS'),'000661.SZ':1,'603392.SS':2, \
|
727
|
-
'300601.SZ':3}
|
728
|
-
today='2020-7-20'
|
729
|
-
future_days=1
|
730
|
-
alpha=0.99
|
731
|
-
pastyears=1
|
732
|
-
model='all'
|
733
|
-
printout=True
|
734
|
-
|
735
|
-
#===========================================================================
|
736
|
-
def ret_Normality_SW(ret_series,siglevel=0.05):
|
737
|
-
"""
|
738
|
-
功能:测试一个投资组合portfolio在给定期间内(fromdate,todate)的收益率序列
|
739
|
-
是否符合正态分布
|
740
|
-
输入参数:投资组合,开始日期,结束日期,显著性要求水平
|
741
|
-
输出:收益率序列正态性检验的W, p-value, Skewness, Kurtosis
|
742
|
-
【Shapiro-Wilk正态性检验】原假设:服从正态分布
|
743
|
-
"""
|
744
|
-
#去掉空值
|
745
|
-
ret_series=ret_series[~ret_series.isnull()]
|
746
|
-
|
747
|
-
from scipy import stats
|
748
|
-
(W,p_value)=stats.shapiro(ret_series)
|
749
|
-
|
750
|
-
S=stats.skew(ret_series)
|
751
|
-
K=stats.kurtosis(ret_series)
|
752
|
-
|
753
|
-
return round(W,4),round(p_value,4),round(S,2),round(K,2)
|
754
|
-
|
755
|
-
#===========================================================================
|
756
|
-
def portfolio_ret_Normality_SW(portfolio,fromdate,todate, \
|
757
|
-
siglevel=0.05,printout=True):
|
758
|
-
"""
|
759
|
-
功能:测试一个投资组合portfolio在给定期间内(fromdate,todate)的收益率序列
|
760
|
-
是否符合正态分布
|
761
|
-
输入参数:投资组合,开始日期,结束日期,显著性要求水平
|
762
|
-
输出:收益率序列正态性检验的p-value
|
763
|
-
【Shapiro-Wilk正态性检验】原假设:服从正态分布
|
764
|
-
"""
|
765
|
-
#抓取投资组合股价和收益率
|
766
|
-
prices=get_portfolio_prices0(portfolio,fromdate,todate)
|
767
|
-
if prices is None: return None,None
|
768
|
-
ret_series=prices['Ret']
|
769
|
-
num=len(prices)-1
|
770
|
-
|
771
|
-
#检验正态分布
|
772
|
-
W,p_value,S,K=ret_Normality_SW(ret_series,siglevel)
|
773
|
-
|
774
|
-
if not printout: return W,p_value,S,K
|
775
|
-
|
776
|
-
_,_,tickerlist,sharelist,ticker_type=decompose_portfolio(portfolio)
|
777
|
-
print("*** Shapiro-Wilk Normality Test ***")
|
778
|
-
print(" Stock(s):",tickerlist)
|
779
|
-
print(" Holding proportion:",sharelist)
|
780
|
-
print(" Sampling period :",fromdate,'to',todate)
|
781
|
-
print(" Observations :",num)
|
782
|
-
print(" Null hypothesis : Normal")
|
783
|
-
print(" W statistic :",round(W,4))
|
784
|
-
print(" p-value :",round(p_value,4))
|
785
|
-
print(" Skewness :",round(S,2))
|
786
|
-
print(" Kurtosis :",round(K,2))
|
787
|
-
if p_value >= siglevel:
|
788
|
-
print("Result: Accept null hypothesis, normal")
|
789
|
-
else:
|
790
|
-
print("Result: Reject null hypothesis, not normal")
|
791
|
-
|
792
|
-
footnote="... Data source: Yahoo Finance"
|
793
|
-
print(footnote)
|
794
|
-
|
795
|
-
return W,p_value,S,K
|
796
|
-
|
797
|
-
#==============================================================================
|
798
|
-
if __name__ == '__main__':
|
799
|
-
portfolio={'Market':('China','000001.SS'),'000661.SZ':0.1,'603392.SS':0.2, \
|
800
|
-
'300601.SZ':0.7}
|
801
|
-
fromdate='2022-1-1'
|
802
|
-
todate='2022-4-18'
|
803
|
-
|
804
|
-
def portfolio_rets_curve(portfolio,start='MRY',end='today'):
|
805
|
-
"""
|
806
|
-
功能:绘制投资组合portfolio在给定期间(fromdate,todate)收益率分布的曲线,
|
807
|
-
并于相应的正态分布图对照
|
808
|
-
显示:收益率分布的直方图(实线),相应的正态分布图(虚线)
|
809
|
-
x轴为收益率(非百分比),y轴为频度(Frequency)
|
810
|
-
"""
|
811
|
-
fromdate,todate=start_end_preprocess(start,end)
|
812
|
-
|
813
|
-
#抓取投资组合股价和收益率
|
814
|
-
prices=get_portfolio_prices0(portfolio,fromdate,todate)
|
815
|
-
if prices is None: return None,None
|
816
|
-
|
817
|
-
num=len(prices)
|
818
|
-
rets=prices['Ret']
|
819
|
-
W,p_value,S,K=ret_Normality_SW(rets)
|
820
|
-
_,_,tickerlist,sharelist,ticker_type=decompose_portfolio(portfolio)
|
821
|
-
#计算收益率的均值和标准差
|
822
|
-
mu=rets.mean()
|
823
|
-
sigma=rets.std()
|
824
|
-
|
825
|
-
#生成符合正态分布的随机数,符合股票收益率的均值和标准差
|
826
|
-
import numpy as np
|
827
|
-
x=mu+sigma*np.random.randn(10000)
|
828
|
-
|
829
|
-
#plt.figure(figsize=(8,4))
|
830
|
-
plt.figure(figsize=(12.8,6.4))
|
831
|
-
import seaborn as sns
|
832
|
-
#绘制曲线:股票收益率
|
833
|
-
sns.kdeplot(data=rets,shade=True,color='blue',legend=True,label='投资组合',lw=4)
|
834
|
-
#绘制曲线:对应的正态分布
|
835
|
-
sns.kdeplot(data=x,shade=True,color='r',legend=True,label='正态分布线',ls='--')
|
836
|
-
#设置标题、图例、坐标轴标签
|
837
|
-
#plt.ylabel('Frequency')
|
838
|
-
|
839
|
-
footnote1='日收益率%'
|
840
|
-
footnote2='\n【注】Shapiro-Wilk检验:W值'+str(W)+',p值'+str(p_value)
|
841
|
-
footnote3="。偏度"+str(S)+",峰度"+str(K)
|
842
|
-
|
843
|
-
import datetime as dt; today=dt.date.today()
|
844
|
-
footnote4="。数据来源:新浪/stooq,"+str(today)
|
845
|
-
|
846
|
-
footnote=footnote1+footnote2+footnote3+footnote4
|
847
|
-
plt.xlabel(footnote)
|
848
|
-
|
849
|
-
plt.legend(loc='best')
|
850
|
-
"""
|
851
|
-
titletxt1="投资组合收益率的正态分布检验"
|
852
|
-
titletxt2="\n成分股"+str(tickerlist)
|
853
|
-
titletxt3="\n持仓配置"+str(sharelist)
|
854
|
-
titletxt4="\n样本期间:"+str(fromdate)+'至'+str(todate)+ \
|
855
|
-
',样本数量'+str(num)+'个'
|
856
|
-
titletxt=titletxt1+titletxt2+titletxt3+titletxt4
|
857
|
-
"""
|
858
|
-
titletxt="投资组合收益率的正态分布检验:"+portfolio_name(portfolio)
|
859
|
-
plt.title(titletxt)
|
860
|
-
|
861
|
-
plt.gca().set_facecolor('whitesmoke')
|
862
|
-
plt.show()
|
863
|
-
|
864
|
-
return
|
865
|
-
|
866
|
-
|
867
|
-
#==============================================================================
|