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,992 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
"""
|
3
|
-
本模块功能:债券,基础层函数
|
4
|
-
所属工具包:证券投资分析工具SIAT
|
5
|
-
SIAT:Security Investment Analysis Tool
|
6
|
-
创建日期:2020年1月8日
|
7
|
-
最新修订日期:2020年5月10日
|
8
|
-
作者:王德宏 (WANG Dehong, Peter)
|
9
|
-
作者单位:北京外国语大学国际商学院
|
10
|
-
版权所有:王德宏
|
11
|
-
用途限制:仅限研究与教学使用,不可商用!商用需要额外授权。
|
12
|
-
特别声明:作者不对使用本工具进行证券投资导致的任何损益负责!
|
13
|
-
"""
|
14
|
-
|
15
|
-
#==============================================================================
|
16
|
-
#关闭所有警告
|
17
|
-
import warnings; warnings.filterwarnings('ignore')
|
18
|
-
from siat.common import *
|
19
|
-
from siat.translate import *
|
20
|
-
#==============================================================================
|
21
|
-
import matplotlib.pyplot as plt
|
22
|
-
#plt.rcParams['figure.figsize']=(12.8,7.2)
|
23
|
-
plt.rcParams['figure.figsize']=(12.8,6.4)
|
24
|
-
plt.rcParams['figure.dpi']=300
|
25
|
-
plt.rcParams['font.size'] = 13
|
26
|
-
plt.rcParams['xtick.labelsize']=11 #横轴字体大小
|
27
|
-
plt.rcParams['ytick.labelsize']=11 #纵轴字体大小
|
28
|
-
|
29
|
-
title_txt_size=16
|
30
|
-
ylabel_txt_size=14
|
31
|
-
xlabel_txt_size=14
|
32
|
-
legend_txt_size=14
|
33
|
-
|
34
|
-
#处理绘图汉字乱码问题
|
35
|
-
import sys; czxt=sys.platform
|
36
|
-
if czxt in ['win32','win64']:
|
37
|
-
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置默认字体
|
38
|
-
mpfrc={'font.family': 'SimHei'}
|
39
|
-
|
40
|
-
if czxt in ['darwin']: #MacOSX
|
41
|
-
plt.rcParams['font.family']= ['Heiti TC']
|
42
|
-
mpfrc={'font.family': 'Heiti TC'}
|
43
|
-
|
44
|
-
if czxt in ['linux']: #website Jupyter
|
45
|
-
plt.rcParams['font.family']= ['Heiti TC']
|
46
|
-
mpfrc={'font.family':'Heiti TC'}
|
47
|
-
|
48
|
-
# 解决保存图像时'-'显示为方块的问题
|
49
|
-
plt.rcParams['axes.unicode_minus'] = False
|
50
|
-
|
51
|
-
#==============================================================================
|
52
|
-
def macD0(cr,ytm,fv,nterms):
|
53
|
-
"""
|
54
|
-
功能:计算债券的麦考莱久期期数
|
55
|
-
输入参数:
|
56
|
-
1、每期票面利率cr
|
57
|
-
2、每期到期收益率ytm,市场利率,贴现率
|
58
|
-
3、票面价值fv
|
59
|
-
3、到期期数nterms
|
60
|
-
输出:麦考莱久期的期数(不一定是年数)
|
61
|
-
"""
|
62
|
-
#生成期数序列
|
63
|
-
import pandas as pd
|
64
|
-
t=pd.Series(range(1,(nterms+1)))
|
65
|
-
|
66
|
-
#计算未来票息和面值的现值
|
67
|
-
p=sum(cr*fv/(1+ytm)**t)+fv/(1+ytm)**len(t)
|
68
|
-
#计算未来票息和面值的加权现值
|
69
|
-
wp=sum(cr*fv*t/(1+ytm)**t)+fv*len(t)/(1+ytm)**len(t)
|
70
|
-
|
71
|
-
return wp/p
|
72
|
-
|
73
|
-
if __name__=='__main__':
|
74
|
-
cr=0.08/2; ytm=0.1/2; nterms=6; fv=100
|
75
|
-
print(macD0(cr,ytm,fv,nterms))
|
76
|
-
#==============================================================================
|
77
|
-
def macD(cr,ytm,nyears,ctimes=2,fv=100):
|
78
|
-
"""
|
79
|
-
功能:计算债券的麦考莱久期年数
|
80
|
-
输入参数:
|
81
|
-
1、年票面利率cr
|
82
|
-
2、年到期收益率ytm,市场利率,贴现率
|
83
|
-
3、到期年数nyears
|
84
|
-
4、每年付息次数ctimes
|
85
|
-
5、票面价值fv
|
86
|
-
输出:麦考莱久期(年数)
|
87
|
-
"""
|
88
|
-
|
89
|
-
#转换为每期付息的参数
|
90
|
-
c=cr/ctimes; y=ytm/ctimes; F=fv; n=nyears*ctimes
|
91
|
-
|
92
|
-
#计算麦考莱久期期数
|
93
|
-
d=macD0(c,y,F,n)
|
94
|
-
#转换为麦考莱久期年数:年数=期数/每年付息次数
|
95
|
-
D=round(d/ctimes,4)
|
96
|
-
|
97
|
-
return D
|
98
|
-
|
99
|
-
if __name__=='__main__':
|
100
|
-
cr=0.08; ytm=0.1; nyears=3; ctimes=2; fv=100
|
101
|
-
print(macD(cr,ytm,nyears))
|
102
|
-
|
103
|
-
#==============================================================================
|
104
|
-
def MD0(cr,ytm,fv,nterms):
|
105
|
-
"""
|
106
|
-
功能:计算债券的修正久期期数
|
107
|
-
输入参数:
|
108
|
-
1、每期票面利率cr
|
109
|
-
2、每期到期收益率ytm,市场利率,贴现率
|
110
|
-
3、票面价值fv
|
111
|
-
4、到期期数nterms
|
112
|
-
输出:修正久期期数(不一定是年数)
|
113
|
-
"""
|
114
|
-
#修正麦考莱久期
|
115
|
-
md=macD0(cr,ytm,fv,nterms)/(1+ytm)
|
116
|
-
|
117
|
-
return md
|
118
|
-
|
119
|
-
if __name__=='__main__':
|
120
|
-
cr=0.08/2; ytm=0.1/2; nterms=6; fv=100
|
121
|
-
print(MD0(cr,ytm,fv,nterms))
|
122
|
-
|
123
|
-
#==============================================================================
|
124
|
-
def MD(cr,ytm,nyears,ctimes=2,fv=100):
|
125
|
-
"""
|
126
|
-
功能:计算债券的修正久期年数
|
127
|
-
输入参数:
|
128
|
-
1、年票面利率cr
|
129
|
-
2、年到期收益率ytm,市场利率,贴现率
|
130
|
-
3、到期年数nyears
|
131
|
-
4、每年付息次数ctimes
|
132
|
-
5、票面价值fv
|
133
|
-
输出:修正久期(年数)
|
134
|
-
"""
|
135
|
-
|
136
|
-
#转换为每期付息的参数
|
137
|
-
c=cr/ctimes; y=ytm/ctimes; F=fv; n=nyears*ctimes
|
138
|
-
|
139
|
-
#计算久期期数
|
140
|
-
d=MD0(c,y,F,n)
|
141
|
-
#转换为久期年数:年数=期数/每年付息次数
|
142
|
-
D=round(d/ctimes,4)
|
143
|
-
|
144
|
-
return D
|
145
|
-
|
146
|
-
if __name__=='__main__':
|
147
|
-
cr=0.08; ytm=0.1; nyears=3; ctimes=2; fv=100
|
148
|
-
print(MD(cr,ytm,nyears))
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
#==============================================================================
|
153
|
-
def DD0(cr,ytm,fv,nterms):
|
154
|
-
"""
|
155
|
-
功能:计算债券的美元久期期数
|
156
|
-
输入参数:
|
157
|
-
1、每期票面利率cr
|
158
|
-
2、每期到期收益率ytm,市场利率,贴现率
|
159
|
-
3、票面价值fv
|
160
|
-
4、到期期数nterms
|
161
|
-
输出:美元久期期数(不一定是年数)
|
162
|
-
"""
|
163
|
-
#生成期数序列
|
164
|
-
import pandas as pd
|
165
|
-
t=pd.Series(range(1,(nterms+1)))
|
166
|
-
|
167
|
-
#计算现值
|
168
|
-
p=sum(cr*fv/(1+ytm)**t)+fv/(1+ytm)**len(t)
|
169
|
-
#美元久期期数
|
170
|
-
dd=MD0(cr,ytm,fv,nterms)*p
|
171
|
-
|
172
|
-
return dd
|
173
|
-
|
174
|
-
if __name__=='__main__':
|
175
|
-
cr=0.08/2; ytm=0.1/2; nterms=6; fv=100
|
176
|
-
print(DD0(cr,ytm,fv,nterms))
|
177
|
-
|
178
|
-
#==============================================================================
|
179
|
-
def DD(cr,ytm,nyears,ctimes=2,fv=100):
|
180
|
-
"""
|
181
|
-
功能:计算债券的美元久期年数
|
182
|
-
输入参数:
|
183
|
-
1、年票面利率cr
|
184
|
-
2、年到期收益率ytm,市场利率,贴现率
|
185
|
-
3、到期年数nyears
|
186
|
-
4、每年付息次数ctimes
|
187
|
-
5、票面价值fv
|
188
|
-
输出:美元久期(金额)
|
189
|
-
"""
|
190
|
-
|
191
|
-
#转换为每期付息的参数
|
192
|
-
c=cr/ctimes; y=ytm/ctimes; F=fv; n=nyears*ctimes
|
193
|
-
|
194
|
-
#计算久期期数
|
195
|
-
d=DD0(c,y,F,n)
|
196
|
-
#转换为久期年数:年数=期数/每年付息次数
|
197
|
-
D=round(d/ctimes,2)
|
198
|
-
|
199
|
-
return D
|
200
|
-
|
201
|
-
if __name__=='__main__':
|
202
|
-
cr=0.08; ytm=0.1; nyears=3; ctimes=2; fv=100
|
203
|
-
print(DD(cr,ytm,nyears))
|
204
|
-
|
205
|
-
#==============================================================================
|
206
|
-
def ED0(cr,ytm,fv,nterms,per):
|
207
|
-
"""
|
208
|
-
功能:计算债券的有效久期期数
|
209
|
-
输入参数:
|
210
|
-
1、每期票面利率cr
|
211
|
-
2、每期到期收益率ytm,市场利率,贴现率
|
212
|
-
3、票面价值fv
|
213
|
-
4、到期期数nterms
|
214
|
-
5、到期收益率的变化幅度,1个基点=0.01%=0.0001
|
215
|
-
输出:有效久期期数(不一定是年数)
|
216
|
-
"""
|
217
|
-
#生成期数序列
|
218
|
-
import pandas as pd
|
219
|
-
t=pd.Series(range(1,(nterms+1)))
|
220
|
-
|
221
|
-
#计算到期收益率变化前的现值
|
222
|
-
p0=sum(cr*fv/(1+ytm)**t)+fv/(1+ytm)**len(t)
|
223
|
-
#计算到期收益率增加一定幅度后的现值
|
224
|
-
p1=sum(cr*fv/(1+ytm+per)**t)+fv/(1+ytm+per)**len(t)
|
225
|
-
#计算到期收益率减少同等幅度后的现值
|
226
|
-
p2=sum(cr*fv/(1+ytm-per)**t)+fv/(1+ytm-per)**len(t)
|
227
|
-
#久期期数
|
228
|
-
try:
|
229
|
-
ed=(p2-p1)/(2*p0*per)
|
230
|
-
except:
|
231
|
-
print(" #Error(ED0): float division by zero")
|
232
|
-
print(" p2=",p2,', p1=',p1,', p0=',p0,', per=',per)
|
233
|
-
return None
|
234
|
-
|
235
|
-
return ed
|
236
|
-
|
237
|
-
if __name__=='__main__':
|
238
|
-
cr=0.08/2; ytm=0.1/2; nterms=6; fv=100; per=0.001/2
|
239
|
-
print(ED0(cr,ytm,fv,nterms,per))
|
240
|
-
|
241
|
-
#==============================================================================
|
242
|
-
def ED(cr,ytm,nyears,peryear,ctimes=2,fv=100):
|
243
|
-
"""
|
244
|
-
功能:计算债券的有效久期年数
|
245
|
-
输入参数:
|
246
|
-
1、年票面利率cr
|
247
|
-
2、年到期收益率ytm,市场利率,贴现率
|
248
|
-
3、到期年数nyears
|
249
|
-
4、年到期收益率变化幅度peryear
|
250
|
-
5、每年付息次数ctimes
|
251
|
-
6、票面价值fv
|
252
|
-
输出:有效久期(年数)
|
253
|
-
"""
|
254
|
-
|
255
|
-
#转换为每期付息的参数
|
256
|
-
c=cr/ctimes; y=ytm/ctimes; per=peryear/ctimes; F=fv; n=nyears*ctimes
|
257
|
-
|
258
|
-
#计算久期期数
|
259
|
-
d=ED0(c,y,F,n,per)
|
260
|
-
#转换为久期年数:年数=期数/每年付息次数
|
261
|
-
D=round(d/ctimes,4)
|
262
|
-
|
263
|
-
return D
|
264
|
-
|
265
|
-
if __name__=='__main__':
|
266
|
-
cr=0.08; ytm=0.1; nyears=3; ctimes=2; fv=100; peryear=0.001
|
267
|
-
print(ED(cr,ytm,nyears,peryear))
|
268
|
-
|
269
|
-
cr=0.095; ytm=0.1144; nyears=8; ctimes=2; fv=1000; peryear=0.0005
|
270
|
-
print(ED(cr,ytm,nyears,peryear))
|
271
|
-
#==============================================================================
|
272
|
-
def CFD0(cr,ytm,fv,nterms):
|
273
|
-
"""
|
274
|
-
功能:计算债券的封闭式久期期数
|
275
|
-
输入参数:
|
276
|
-
1、每期票面利率cr
|
277
|
-
2、每期到期收益率ytm,市场利率,贴现率
|
278
|
-
3、票面价值fv
|
279
|
-
4、到期期数nterms
|
280
|
-
输出:久期期数(不一定是年数)
|
281
|
-
"""
|
282
|
-
#生成期数序列
|
283
|
-
import pandas as pd
|
284
|
-
t=pd.Series(range(1,(nterms+1)))
|
285
|
-
|
286
|
-
#计算到期收益率变化前的现值
|
287
|
-
p=sum(cr*fv/(1+ytm)**t)+fv/(1+ytm)**len(t)
|
288
|
-
|
289
|
-
#计算分子第1项
|
290
|
-
nm1=(cr*fv) * ((1+ytm)**(nterms+1)-(1+ytm)-ytm*nterms) / ((ytm**2)*((1+ytm)**nterms))
|
291
|
-
#计算分子第2项
|
292
|
-
nm2=fv*(nterms/((1+ytm)**nterms))
|
293
|
-
|
294
|
-
#计算封闭式久期
|
295
|
-
cfd=(nm1+nm2)/p
|
296
|
-
|
297
|
-
return cfd
|
298
|
-
|
299
|
-
if __name__=='__main__':
|
300
|
-
cr=0.095/2; ytm=0.1144/2; nterms=16; fv=1000
|
301
|
-
print(CFD0(cr,ytm,fv,nterms))
|
302
|
-
#==============================================================================
|
303
|
-
def CFD(cr,ytm,nyears,ctimes=2,fv=100):
|
304
|
-
"""
|
305
|
-
功能:计算债券的封闭式年数
|
306
|
-
输入参数:
|
307
|
-
1、年票面利率cr
|
308
|
-
2、年到期收益率ytm,市场利率,贴现率
|
309
|
-
3、到期年数nyears
|
310
|
-
4、每年付息次数ctimes
|
311
|
-
5、票面价值fv
|
312
|
-
输出:久期(年数)
|
313
|
-
"""
|
314
|
-
|
315
|
-
#转换为每期付息的参数
|
316
|
-
c=cr/ctimes; y=ytm/ctimes; F=fv; n=nyears*ctimes
|
317
|
-
|
318
|
-
#计算久期期数
|
319
|
-
d=CFD0(c,y,F,n)
|
320
|
-
#转换为久期年数:年数=期数/每年付息次数
|
321
|
-
cfd=round(d/ctimes,4)
|
322
|
-
|
323
|
-
return cfd
|
324
|
-
|
325
|
-
if __name__=='__main__':
|
326
|
-
cr=0.08; ytm=0.1; nyears=3; ctimes=2; fv=100
|
327
|
-
print(CFD(cr,ytm,nyears))
|
328
|
-
#==============================================================================
|
329
|
-
def C0(cr,ytm,fv,nterms):
|
330
|
-
"""
|
331
|
-
功能:计算债券的凸度期数
|
332
|
-
输入参数:
|
333
|
-
1、每期票面利率cr
|
334
|
-
2、每期到期收益率ytm,市场利率,贴现率
|
335
|
-
3、票面价值fv
|
336
|
-
4、到期期数nterms
|
337
|
-
输出:到期收益率变化幅度为per时债券价格的变化幅度
|
338
|
-
"""
|
339
|
-
#生成期数序列
|
340
|
-
import pandas as pd
|
341
|
-
t=pd.Series(range(1,(nterms+1)))
|
342
|
-
|
343
|
-
#计算未来现金流的现值
|
344
|
-
p=sum(cr*fv/(1+ytm)**t)+fv/(1+ytm)**len(t)
|
345
|
-
#计算未来现金流的加权现值:权重为第t期的(t**2+t)
|
346
|
-
w2p=sum(cr*fv*(t**2+t)/(1+ytm)**t)+fv*(len(t)**2+len(t))/(1+ytm)**len(t)
|
347
|
-
#计算凸度
|
348
|
-
c0=w2p/(p*(1+ytm)**2)
|
349
|
-
|
350
|
-
return c0
|
351
|
-
|
352
|
-
if __name__=='__main__':
|
353
|
-
cr=0.08/2; ytm=0.1/2; nterms=6; fv=100
|
354
|
-
print(C0(cr,ytm,fv,nterms))
|
355
|
-
#==============================================================================
|
356
|
-
def convexity(cr,ytm,nyears,ctimes=2,fv=100):
|
357
|
-
"""
|
358
|
-
功能:计算债券的凸度年数
|
359
|
-
输入参数:
|
360
|
-
1、年票面利率cr
|
361
|
-
2、年到期收益率ytm,市场利率,贴现率
|
362
|
-
3、到期年数nyears
|
363
|
-
4、每年付息次数ctimes
|
364
|
-
5、票面价值fv
|
365
|
-
输出:凸度(年数)
|
366
|
-
"""
|
367
|
-
#转换为每期付息的参数
|
368
|
-
c=cr/ctimes; y=ytm/ctimes; F=fv; n=nyears*ctimes
|
369
|
-
|
370
|
-
#计算凸度期数
|
371
|
-
c=C0(c,y,F,n)
|
372
|
-
#转换为凸度年数:年数=期数/每年付息次数**2
|
373
|
-
cyears=round(c/ctimes**2,4)
|
374
|
-
|
375
|
-
return cyears
|
376
|
-
|
377
|
-
if __name__=='__main__':
|
378
|
-
cr=0.08; ytm=0.1; nyears=3; ctimes=2; fv=100
|
379
|
-
print(convexity(cr,ytm,nyears))
|
380
|
-
#==============================================================================
|
381
|
-
if __name__=='__main__':
|
382
|
-
coupon_rate=0.07
|
383
|
-
maturity_years=8
|
384
|
-
ytm=0.06
|
385
|
-
coupon_times=2
|
386
|
-
par_value=100
|
387
|
-
rate_diff=0.005
|
388
|
-
|
389
|
-
dp=interest_rate_risk(coupon_rate,maturity_years,ytm,rate_diff)
|
390
|
-
|
391
|
-
def interest_rate_risk(coupon_rate,maturity_years,ytm,rate_diff, \
|
392
|
-
coupon_times=2,par_value=100,printout=True):
|
393
|
-
"""
|
394
|
-
功能:若市场利率变化(上升/下降)rate_change(Δr),导致债券市价的变化率(ΔP/P)
|
395
|
-
原理:债券市场价格的久期与凸度展开公式
|
396
|
-
注意:套壳函数ytm_risk
|
397
|
-
"""
|
398
|
-
|
399
|
-
value=ytm_risk(cr=coupon_rate,ytm=ytm,nyears=maturity_years, \
|
400
|
-
bpyear=rate_diff,ctimes=coupon_times,fv=par_value)
|
401
|
-
|
402
|
-
if printout:
|
403
|
-
calc_durations(coupon_rate,maturity_years,ytm,
|
404
|
-
coupon_times=coupon_times,par_value=par_value, \
|
405
|
-
mtypes=['macaulay_duration','convexity'])
|
406
|
-
|
407
|
-
if (rate_diff !=0) and (value !=0):
|
408
|
-
print("\n***利率变化带来的风险")
|
409
|
-
|
410
|
-
if rate_diff > 0:
|
411
|
-
arrow='↑'
|
412
|
-
elif rate_diff < 0:
|
413
|
-
arrow='↓'
|
414
|
-
else:
|
415
|
-
arrow=' '
|
416
|
-
if rate_diff !=0:
|
417
|
-
print("市场利率变化(基点):",int(rate_diff*10000),arrow)
|
418
|
-
|
419
|
-
if value > 0:
|
420
|
-
arrow2='↑'
|
421
|
-
elif value < 0:
|
422
|
-
arrow2='↓'
|
423
|
-
else:
|
424
|
-
arrow2=' '
|
425
|
-
if value !=0:
|
426
|
-
print("债券市价的变化率 :",round(value*100,2),'\b% '+arrow2)
|
427
|
-
|
428
|
-
return value
|
429
|
-
|
430
|
-
#==============================================================================
|
431
|
-
def ytm_risk(cr,ytm,nyears,bpyear,ctimes=2,fv=100):
|
432
|
-
"""
|
433
|
-
功能:计算债券的利率风险,即市场利率(到期收益率)变动将带来的债券价格变化率
|
434
|
-
输入参数:
|
435
|
-
1、年票面利率cr
|
436
|
-
2、年到期收益率ytm,市场利率,贴现率
|
437
|
-
3、到期年数nyears
|
438
|
-
4、年华市场利率(到期收益率)变化的幅度bpyear(小数,不是基点)
|
439
|
-
5、每年付息次数ctimes
|
440
|
-
6、票面价值fv
|
441
|
-
输出:到期收益率变化幅度导致的债券价格变化率
|
442
|
-
"""
|
443
|
-
#转换为每期付息的参数
|
444
|
-
c=cr/ctimes; y=ytm/ctimes; F=fv; n=nyears*ctimes
|
445
|
-
|
446
|
-
#计算到期收益率变化对债券价格的影响:第1部分
|
447
|
-
b0=-MD0(c,y,F,n)/2*bpyear
|
448
|
-
#计算到期收益率变化对债券价格的影响:第2部分
|
449
|
-
b1=(0.5*C0(c,y,F,n)/ctimes**2)*bpyear**2
|
450
|
-
#债券价格的变化率
|
451
|
-
p_pct=round(b0+b1,4)
|
452
|
-
|
453
|
-
return p_pct
|
454
|
-
|
455
|
-
if __name__=='__main__':
|
456
|
-
cr=0.08; ytm=0.1; nyears=3; bpyear=0.01
|
457
|
-
print(ytm_risk(cr,ytm,nyears,bpyear))
|
458
|
-
|
459
|
-
#==============================================================================
|
460
|
-
#==============================================================================
|
461
|
-
def interbank_bond_issue_detail(fromdate,todate):
|
462
|
-
"""
|
463
|
-
功能:获得银行间债券市场发行明细
|
464
|
-
输入:开始日期fromdate,截止日期todate
|
465
|
-
"""
|
466
|
-
#检查期间的合理性
|
467
|
-
result,start,end=check_period(fromdate, todate)
|
468
|
-
if result is None:
|
469
|
-
print(" #Error(interbank_bond_issue_detail), invalid period:",fromdate,todate)
|
470
|
-
return None
|
471
|
-
|
472
|
-
#####银行间市场的债券发行数据
|
473
|
-
import akshare as ak
|
474
|
-
#获得债券发行信息第1页
|
475
|
-
print("\n...Searching for bond issuance: ",end='')
|
476
|
-
bond_issue=ak.get_bond_bank(page_num=1)
|
477
|
-
|
478
|
-
import pandas as pd
|
479
|
-
from datetime import datetime
|
480
|
-
#获得债券发行信息后续页
|
481
|
-
maxpage=999
|
482
|
-
for pn in range(2,maxpage):
|
483
|
-
print_progress_bar(pn,2,maxpage)
|
484
|
-
try:
|
485
|
-
#防止中间一次失败导致整个过程失败
|
486
|
-
bi=ak.get_bond_bank(page_num=pn)
|
487
|
-
try:
|
488
|
-
bond_issue=bond_issue.append(bi)
|
489
|
-
except:
|
490
|
-
bond_issue=bond_issue._append(bi)
|
491
|
-
except:
|
492
|
-
#后续的网页已经变得无法抓取
|
493
|
-
print("...Unexpected get_bond_bank(interbank_bond_issue_detail), page_num",pn)
|
494
|
-
break
|
495
|
-
|
496
|
-
#判断是否超过了开始日期
|
497
|
-
bistartdate=bi.tail(1)['releaseTime'].values[0]
|
498
|
-
bistartdate2=pd.to_datetime(bistartdate)
|
499
|
-
if bistartdate2 < start: break
|
500
|
-
print(" Done!")
|
501
|
-
|
502
|
-
#删除重复项,按日期排序
|
503
|
-
bond_issue.drop_duplicates(keep='first',inplace=True)
|
504
|
-
bond_issue.sort_values(by=['releaseTime'],ascending=[False],inplace=True)
|
505
|
-
#转换日期项
|
506
|
-
lway1=lambda x: datetime.strptime(x,'%Y-%m-%d %H:%M:%S')
|
507
|
-
bond_issue['releaseTime2']=bond_issue['releaseTime'].apply(lway1)
|
508
|
-
|
509
|
-
#提取年月日信息
|
510
|
-
lway2=lambda x: x.year
|
511
|
-
bond_issue['releaseYear']=bond_issue['releaseTime2'].map(lway2).astype('str')
|
512
|
-
lway3=lambda x: x.month
|
513
|
-
bond_issue['releaseMonth']=bond_issue['releaseTime2'].map(lway3).astype('str')
|
514
|
-
lway4=lambda x: x.day
|
515
|
-
bond_issue['releaseDay']=bond_issue['releaseTime2'].map(lway4).astype('str')
|
516
|
-
lway5=lambda x: x.weekday() + 1
|
517
|
-
bond_issue['releaseWeekDay']=bond_issue['releaseTime2'].map(lway5).astype('str')
|
518
|
-
lway6=lambda x: x.date()
|
519
|
-
bond_issue['releaseDate']=bond_issue['releaseTime2'].map(lway6).astype('str')
|
520
|
-
|
521
|
-
#过滤日期
|
522
|
-
bond_issue=bond_issue.reset_index(drop = True)
|
523
|
-
bond_issue1=bond_issue.drop(bond_issue[bond_issue['releaseTime2']<start].index)
|
524
|
-
bond_issue1=bond_issue1.reset_index(drop = True)
|
525
|
-
bond_issue2=bond_issue1.drop(bond_issue1[bond_issue1['releaseTime2']>end].index)
|
526
|
-
bond_issue2=bond_issue2.reset_index(drop = True)
|
527
|
-
#转换字符串到金额
|
528
|
-
bond_issue2['issueAmount']=bond_issue2['firstIssueAmount'].astype('float64')
|
529
|
-
|
530
|
-
return bond_issue2
|
531
|
-
|
532
|
-
if __name__=='__main__':
|
533
|
-
fromdate='2020-4-25'
|
534
|
-
todate='2020-4-28'
|
535
|
-
ibbi=interbank_bond_issue_detail(fromdate,todate)
|
536
|
-
|
537
|
-
#==============================================================================
|
538
|
-
#==============================================================================
|
539
|
-
#==============================================================================
|
540
|
-
# 演示久期、凸度的影响因素
|
541
|
-
#==============================================================================
|
542
|
-
if __name__=='__main__':
|
543
|
-
coupon_rate=0.07
|
544
|
-
maturity_years=8
|
545
|
-
ytm=0.06
|
546
|
-
coupon_times=2
|
547
|
-
par_value=100
|
548
|
-
rate_change=0.0001
|
549
|
-
mtype='macaulay_duration'
|
550
|
-
|
551
|
-
calc_macaulay(coupon_rate,maturity_years,ytm,mtype='macaulay_duration')
|
552
|
-
calc_macaulay(coupon_rate,maturity_years,ytm,mtype='modified_duration')
|
553
|
-
calc_macaulay(coupon_rate,maturity_years,ytm,mtype='dollar_duration')
|
554
|
-
calc_macaulay(coupon_rate,maturity_years,ytm,mtype='efficient_duration')
|
555
|
-
calc_macaulay(coupon_rate,maturity_years,ytm,mtype='closed_form_duration')
|
556
|
-
calc_macaulay(coupon_rate,maturity_years,ytm,mtype='convexity')
|
557
|
-
|
558
|
-
calc_macaulay(0.1,3,0.12,1,1000,'macaulay_duration')
|
559
|
-
calc_macaulay(0.1,3,0.05,1,1000,'macaulay_duration')
|
560
|
-
calc_macaulay(0.1,3,0.20,1,1000,'macaulay_duration')
|
561
|
-
|
562
|
-
calc_macaulay(0.08,3,0.1,2,100,'closed_form_duration')
|
563
|
-
|
564
|
-
calc_macaulay(0.08,3,0.1,2,100,'modified_duration')
|
565
|
-
calc_macaulay(0.08,3,0.1,2,100,'dollar_duration')
|
566
|
-
|
567
|
-
calc_macaulay(0.095,8,0.1144,2,1000,'efficient_duration',rate_change=0.0005)
|
568
|
-
|
569
|
-
calc_macaulay(0.08,3,0.1,2,100,'convexity')
|
570
|
-
|
571
|
-
def calc_macaulay(coupon_rate,maturity_years,ytm,
|
572
|
-
coupon_times=2,par_value=100, \
|
573
|
-
mtype='macaulay_duration', \
|
574
|
-
rate_change=0.001):
|
575
|
-
"""
|
576
|
-
功能:统一计算各种久期和凸度
|
577
|
-
输入参数:
|
578
|
-
coupon_rate:债券的票面年利率
|
579
|
-
maturity_years:距离到期的年数,需要折算
|
580
|
-
ytm:年到期收益率,可作为折现率
|
581
|
-
coupon_times=2:每年付息次数
|
582
|
-
par_value=100:债券面值
|
583
|
-
rate_change=0:利率变化,专用于有效久期
|
584
|
-
mtype='macaulay':麦考利久期macaulay_duration,修正久期modified_duration,
|
585
|
-
美元久期dollar_duration,有效久期efficient_duration,
|
586
|
-
封闭久期closed_form_duration,凸度convexity
|
587
|
-
printout=False:是否打印结果
|
588
|
-
"""
|
589
|
-
|
590
|
-
# 检查计算类型
|
591
|
-
mtypelist=['macaulay_duration','modified_duration','dollar_duration', \
|
592
|
-
'efficient_duration','closed_form_duration','convexity']
|
593
|
-
if not (mtype in mtypelist):
|
594
|
-
print(" #Error(calc_macaulay): unsupported duration/convexity",mtype)
|
595
|
-
print(" Supported duration/convexity:",mtypelist)
|
596
|
-
return None
|
597
|
-
|
598
|
-
value=999
|
599
|
-
# 麦考利久期:返回久期年数
|
600
|
-
if mtype=='macaulay_duration':
|
601
|
-
value=macD(cr=coupon_rate,ytm=ytm,nyears=maturity_years, \
|
602
|
-
ctimes=coupon_times,fv=par_value)
|
603
|
-
|
604
|
-
# 修正久期:返回年数
|
605
|
-
if mtype=='modified_duration':
|
606
|
-
value=MD(cr=coupon_rate,ytm=ytm,nyears=maturity_years, \
|
607
|
-
ctimes=coupon_times,fv=par_value)
|
608
|
-
|
609
|
-
# 美元久期:返回金额
|
610
|
-
if mtype=='dollar_duration':
|
611
|
-
#DD(cr,ytm,nyears,ctimes=2,fv=100)
|
612
|
-
value=DD(cr=coupon_rate,ytm=ytm,nyears=maturity_years, \
|
613
|
-
ctimes=coupon_times,fv=par_value)
|
614
|
-
|
615
|
-
# 有效久期:返回年数
|
616
|
-
if mtype=='efficient_duration':
|
617
|
-
#ED(cr,ytm,nyears,peryear,ctimes=2,fv=100)
|
618
|
-
value=ED(cr=coupon_rate,ytm=ytm,nyears=maturity_years, \
|
619
|
-
peryear=rate_change, \
|
620
|
-
ctimes=coupon_times,fv=par_value)
|
621
|
-
|
622
|
-
# 封闭久期:返回年数
|
623
|
-
if mtype=='closed_form_duration':
|
624
|
-
#CFD(cr,ytm,nyears,ctimes=2,fv=100)
|
625
|
-
value=CFD(cr=coupon_rate,ytm=ytm,nyears=maturity_years, \
|
626
|
-
ctimes=coupon_times,fv=par_value)
|
627
|
-
|
628
|
-
# 凸度:返回年数
|
629
|
-
if mtype=='convexity':
|
630
|
-
#convexity(cr,ytm,nyears,ctimes=2,fv=100)
|
631
|
-
value=convexity(cr=coupon_rate,ytm=ytm,nyears=maturity_years, \
|
632
|
-
ctimes=coupon_times,fv=par_value)
|
633
|
-
|
634
|
-
if value==999:
|
635
|
-
print(" #Error(calc_macaulay): no valid result calculated!")
|
636
|
-
return None
|
637
|
-
|
638
|
-
return value
|
639
|
-
|
640
|
-
|
641
|
-
#==============================================================================
|
642
|
-
if __name__=='__main__':
|
643
|
-
coupon_rate=0.08
|
644
|
-
maturity_years=3
|
645
|
-
ytm=0.1
|
646
|
-
coupon_times=2
|
647
|
-
par_value=100
|
648
|
-
rate_change=0.0005
|
649
|
-
|
650
|
-
calc_durations(coupon_rate,maturity_years,ytm)
|
651
|
-
|
652
|
-
"""
|
653
|
-
def calc_durations(coupon_rate,maturity_years,ytm,
|
654
|
-
coupon_times=2,par_value=100, \
|
655
|
-
mtypes=['macaulay_duration','modified_duration', \
|
656
|
-
'dollar_duration'], \
|
657
|
-
rate_change=0.001):
|
658
|
-
"""
|
659
|
-
def calc_durations(coupon_rate,maturity_years,ytm,
|
660
|
-
coupon_times=1,par_value=100, \
|
661
|
-
mtypes=['macaulay_duration'], \
|
662
|
-
rate_change=0.001):
|
663
|
-
"""
|
664
|
-
功能:一次性计算常见的久期,并打印
|
665
|
-
注意:默认仅处理麦考利久期。若要处理其他久期,可以规定mtypes列表中的选项
|
666
|
-
"""
|
667
|
-
|
668
|
-
mtypes_all=['macaulay_duration','modified_duration', \
|
669
|
-
'efficient_duration','closed_form_duration','dollar_duration', \
|
670
|
-
'convexity']
|
671
|
-
mtypes_all_cn=['麦考利久期(年数):','修正久期(年数) :', \
|
672
|
-
'有效久期(年数) :','封闭久期(年数) :','美元久期(金额) :', \
|
673
|
-
'凸度(年数) :']
|
674
|
-
|
675
|
-
#print("\n===== 久期计算 =====")
|
676
|
-
print("\n***债券信息")
|
677
|
-
print("面值 :",par_value)
|
678
|
-
print("票面利率(年化) :",round(coupon_rate*100,2),'\b%')
|
679
|
-
print("每年付息次数 :",coupon_times)
|
680
|
-
print("到期时间(年数) :",maturity_years)
|
681
|
-
print("到期收益率(年化):",round(ytm*100,2),'\b%')
|
682
|
-
|
683
|
-
if 'efficient_duration' in mtypes:
|
684
|
-
print("假如年利率变化(基点):",rate_change*10000)
|
685
|
-
|
686
|
-
print("\n***计算结果")
|
687
|
-
for mt in mtypes:
|
688
|
-
value=calc_macaulay(coupon_rate,maturity_years,ytm,
|
689
|
-
coupon_times,par_value, \
|
690
|
-
mtype=mt, \
|
691
|
-
rate_change=rate_change)
|
692
|
-
|
693
|
-
pos=mtypes_all.index(mt)
|
694
|
-
value_label=mtypes_all_cn[pos]
|
695
|
-
|
696
|
-
print(value_label,value)
|
697
|
-
|
698
|
-
return
|
699
|
-
|
700
|
-
#==============================================================================
|
701
|
-
|
702
|
-
|
703
|
-
def calc_convexity(coupon_rate,maturity_years,ytm,
|
704
|
-
coupon_times=1,par_value=100):
|
705
|
-
"""
|
706
|
-
功能:用于计算债券的凸度,并打印
|
707
|
-
注意:套壳函数calc_durations
|
708
|
-
"""
|
709
|
-
calc_durations(coupon_rate,maturity_years,ytm,
|
710
|
-
coupon_times=coupon_times,par_value=par_value, \
|
711
|
-
mtypes=['convexity'])
|
712
|
-
|
713
|
-
return
|
714
|
-
|
715
|
-
#==============================================================================
|
716
|
-
# 久期与凸度影响因素的展示
|
717
|
-
#==============================================================================
|
718
|
-
if __name__=='__main__':
|
719
|
-
coupon_rate=0.1
|
720
|
-
maturity_years=3
|
721
|
-
ytm=0.12
|
722
|
-
coupon_times=1
|
723
|
-
par_value=1000
|
724
|
-
mtype='macaulay_duration'
|
725
|
-
change_type='coupon_rate'
|
726
|
-
coupon_rate_change=[-250,-200,-150,-100,-50,50,100,150,200,250]
|
727
|
-
maturity_years_change=[-5,-4,-3,-2,-1,1,2,3,4,5,6,7,8,9,10]
|
728
|
-
ytm_change=[-100,-80,-60,-40,-20,20,40,60,80,100]
|
729
|
-
coupon_times_list=[1,2,4,6,12,24]
|
730
|
-
|
731
|
-
df=macaulay_theorem(coupon_rate,maturity_years,ytm,coupon_times,mtype='macaulay_duration')
|
732
|
-
df=macaulay_theorem(coupon_rate,maturity_years,ytm,coupon_times,change_type='maturity_years')
|
733
|
-
df=macaulay_theorem(coupon_rate,maturity_years,ytm,coupon_times,change_type='ytm')
|
734
|
-
df=macaulay_theorem(coupon_rate,maturity_years,ytm,coupon_times,change_type='coupon_times')
|
735
|
-
|
736
|
-
mtype='modified_duration'
|
737
|
-
df=macaulay_theorem(coupon_rate,maturity_years,ytm,coupon_times,mtype='modified_duration')
|
738
|
-
df=macaulay_theorem(coupon_rate,maturity_years,ytm,coupon_times,mtype='dollar_duration')
|
739
|
-
df=macaulay_theorem(coupon_rate,maturity_years,ytm,coupon_times,mtype='efficient_duration')
|
740
|
-
df=macaulay_theorem(coupon_rate,maturity_years,ytm,coupon_times,mtype='closed_form_duration')
|
741
|
-
df=macaulay_theorem(coupon_rate,maturity_years,ytm,coupon_times,mtype='convexity')
|
742
|
-
|
743
|
-
def macaulay_theorem(
|
744
|
-
coupon_rate,
|
745
|
-
maturity_years,
|
746
|
-
ytm,
|
747
|
-
coupon_times=2,
|
748
|
-
par_value=1000,
|
749
|
-
mtype='macaulay_duration',#麦考利久期
|
750
|
-
change_type='coupon_rate', #变化的因素
|
751
|
-
#coupon_rate_change=[-250,-200,-150,-100,-50,50,100,150,200,250],#基点
|
752
|
-
coupon_rate_change=[-100,-80,-60,-40,-20,20,40,60,80,100],#基点
|
753
|
-
maturity_years_change=[-5,-4,-3,-2,-1,1,2,3,4,5,6,7,8,9,10],#到期年数
|
754
|
-
ytm_change=[-100,-80,-60,-40,-20,20,40,60,80,100],#基点
|
755
|
-
coupon_times_list=[1,2,4,6,12,24],#每年票息发放次数
|
756
|
-
):
|
757
|
-
|
758
|
-
"""
|
759
|
-
功能:绘制久期/凸度受到各种因素变化的影响:票息率,到期年数,市场利率,每年票息次数
|
760
|
-
"""
|
761
|
-
|
762
|
-
# 检查计算类型
|
763
|
-
mtype_list=['macaulay_duration','modified_duration','dollar_duration', \
|
764
|
-
'efficient_duration','closed_form_duration','convexity']
|
765
|
-
if not (mtype in mtype_list):
|
766
|
-
print(" #Error(macaulay_theorem): unsupported duration/convexity",mtype)
|
767
|
-
print(" Supported:",mtype_list)
|
768
|
-
return None
|
769
|
-
|
770
|
-
# 检查因素项目
|
771
|
-
change_type_list=['coupon_rate','maturity_years','ytm','coupon_times']
|
772
|
-
if not (change_type in change_type_list):
|
773
|
-
print(" #Error(macaulay_theorem): unsupported risk factor",change_type)
|
774
|
-
print(" Supported:",change_type_list)
|
775
|
-
return None
|
776
|
-
|
777
|
-
# 其他检查
|
778
|
-
if mtype=='efficient_duration' and change_type!='ytm':
|
779
|
-
print(" #Warning(macaulay_theorem): 有效久期仅适用于到期收益率(市场利率)的变化")
|
780
|
-
return None
|
781
|
-
|
782
|
-
import pandas as pd
|
783
|
-
df=pd.DataFrame(columns=('coupon_rate','maturity_years', \
|
784
|
-
'ytm','coupon_times','par_value',mtype))
|
785
|
-
# 计算因素未改变时的久期或凸度
|
786
|
-
p0=calc_macaulay(coupon_rate=coupon_rate,maturity_years=maturity_years, \
|
787
|
-
ytm=ytm,coupon_times=coupon_times,par_value=par_value, \
|
788
|
-
mtype=mtype,rate_change=0)
|
789
|
-
s=pd.Series({'coupon_rate':coupon_rate,'maturity_years':maturity_years, \
|
790
|
-
'ytm':ytm,'coupon_times':coupon_times,'par_value':par_value, \
|
791
|
-
mtype:p0})
|
792
|
-
try:
|
793
|
-
df=df.append(s, ignore_index=True)
|
794
|
-
except:
|
795
|
-
df=df._append(s, ignore_index=True)
|
796
|
-
|
797
|
-
# 改变风险因素1:票息率
|
798
|
-
if change_type == 'coupon_rate':
|
799
|
-
factor_list=[]
|
800
|
-
for f in coupon_rate_change:
|
801
|
-
f1=round(coupon_rate + f/10000,4)
|
802
|
-
if f1 <= 0: continue
|
803
|
-
factor_list=factor_list + [f1]
|
804
|
-
|
805
|
-
for f1 in factor_list:
|
806
|
-
p1=calc_macaulay(coupon_rate=f1,maturity_years=maturity_years, \
|
807
|
-
ytm=ytm,coupon_times=coupon_times,par_value=par_value, \
|
808
|
-
mtype=mtype,rate_change=0)
|
809
|
-
s=pd.Series({'coupon_rate':f1,'maturity_years':maturity_years, \
|
810
|
-
'ytm':ytm,'coupon_times':coupon_times,'par_value':par_value, \
|
811
|
-
mtype:p1})
|
812
|
-
try:
|
813
|
-
df=df.append(s, ignore_index=True)
|
814
|
-
except:
|
815
|
-
df=df._append(s, ignore_index=True)
|
816
|
-
|
817
|
-
#按照升序排序
|
818
|
-
df.sort_values(by=[change_type],ascending=[True],inplace=True)
|
819
|
-
#指定索引
|
820
|
-
df.reset_index(drop=True,inplace=True)
|
821
|
-
|
822
|
-
# 变化百分比:限coupon_rate和ytm
|
823
|
-
df['coupon_rate%']=df['coupon_rate'].apply(lambda x:round(x*100,2))
|
824
|
-
df['ytm%']=df['ytm'].apply(lambda x:round(x*100,2))
|
825
|
-
|
826
|
-
# 绘图,横轴数值转换为字符串,以便逐点显示
|
827
|
-
df['coupon_rate%_str']=df['coupon_rate%'].astype(str)
|
828
|
-
plt.plot(df['coupon_rate%_str'],df[mtype],color='red',marker='o')
|
829
|
-
|
830
|
-
# 绘制竖线
|
831
|
-
xpos=str(round(coupon_rate*100,2))
|
832
|
-
ymax=df[mtype]
|
833
|
-
ymin=min(df[mtype])
|
834
|
-
plt.vlines(x=xpos,ymin=ymin,ymax=p0,ls=":",colors="blue")
|
835
|
-
|
836
|
-
titletxt="债券的利率风险:票息率变化的影响"
|
837
|
-
footnote1='票息率%'
|
838
|
-
|
839
|
-
# 改变风险因素2:到期年数
|
840
|
-
if change_type == 'maturity_years':
|
841
|
-
factor_list=[]
|
842
|
-
for f in maturity_years_change:
|
843
|
-
f1=maturity_years + f
|
844
|
-
if f1 <= 0: continue
|
845
|
-
factor_list=factor_list + [f1]
|
846
|
-
|
847
|
-
for f1 in factor_list:
|
848
|
-
p1=calc_macaulay(coupon_rate=coupon_rate,maturity_years=f1, \
|
849
|
-
ytm=ytm,coupon_times=coupon_times,par_value=par_value, \
|
850
|
-
mtype=mtype,rate_change=0)
|
851
|
-
s=pd.Series({'coupon_rate':coupon_rate,'maturity_years':f1, \
|
852
|
-
'ytm':ytm,'coupon_times':coupon_times,'par_value':par_value, \
|
853
|
-
mtype:p1})
|
854
|
-
try:
|
855
|
-
df=df.append(s, ignore_index=True)
|
856
|
-
except:
|
857
|
-
df=df._append(s, ignore_index=True)
|
858
|
-
|
859
|
-
#按照升序排序
|
860
|
-
df.sort_values(by=[change_type],ascending=[True],inplace=True)
|
861
|
-
#指定索引
|
862
|
-
df.reset_index(drop=True,inplace=True)
|
863
|
-
|
864
|
-
# 变化百分比:限coupon_rate和ytm
|
865
|
-
df['coupon_rate%']=df['coupon_rate'].apply(lambda x:round(x*100,2))
|
866
|
-
df['ytm%']=df['ytm'].apply(lambda x:round(x*100,2))
|
867
|
-
|
868
|
-
# 绘图,横轴数值转换为字符串,以便逐点显示
|
869
|
-
df['maturity_years_str']=df['maturity_years'].astype(str)
|
870
|
-
plt.plot(df['maturity_years_str'],df[mtype],color='red',marker='o')
|
871
|
-
|
872
|
-
# 绘制竖线
|
873
|
-
xpos=str(maturity_years)+'.0' #为匹配字符串形式的年数
|
874
|
-
ymax=df[mtype]
|
875
|
-
ymin=min(df[mtype])
|
876
|
-
plt.vlines(x=xpos,ymin=ymin,ymax=p0,ls=":",colors="blue")
|
877
|
-
|
878
|
-
titletxt="债券的利率风险:到期年数变化的影响"
|
879
|
-
footnote1='到期年数'
|
880
|
-
|
881
|
-
# 改变风险因素3:市场利率/到期收益率
|
882
|
-
if change_type == 'ytm':
|
883
|
-
factor_list=[]
|
884
|
-
for f in ytm_change:
|
885
|
-
f1=round(ytm + f/10000,4)
|
886
|
-
if f1 <= 0: continue
|
887
|
-
factor_list=factor_list + [f1]
|
888
|
-
|
889
|
-
for f1 in factor_list:
|
890
|
-
p1=calc_macaulay(coupon_rate=coupon_rate,maturity_years=maturity_years, \
|
891
|
-
ytm=f1,coupon_times=coupon_times,par_value=par_value, \
|
892
|
-
mtype=mtype,rate_change=0)
|
893
|
-
s=pd.Series({'coupon_rate':coupon_rate,'maturity_years':maturity_years, \
|
894
|
-
'ytm':f1,'coupon_times':coupon_times,'par_value':par_value, \
|
895
|
-
mtype:p1})
|
896
|
-
try:
|
897
|
-
df=df.append(s, ignore_index=True)
|
898
|
-
except:
|
899
|
-
df=df._append(s, ignore_index=True)
|
900
|
-
|
901
|
-
#按照升序排序
|
902
|
-
df.sort_values(by=[change_type],ascending=[True],inplace=True)
|
903
|
-
#指定索引
|
904
|
-
df.reset_index(drop=True,inplace=True)
|
905
|
-
|
906
|
-
# 变化百分比:限coupon_rate和ytm
|
907
|
-
df['coupon_rate%']=df['coupon_rate'].apply(lambda x:round(x*100,2))
|
908
|
-
df['ytm%']=df['ytm'].apply(lambda x:round(x*100,2))
|
909
|
-
|
910
|
-
# 绘图,横轴数值转换为字符串,以便逐点显示
|
911
|
-
df['ytm%_str']=df['ytm%'].astype(str)
|
912
|
-
plt.plot(df['ytm%_str'],df[mtype],color='red',marker='o')
|
913
|
-
|
914
|
-
# 绘制竖线
|
915
|
-
xpos=str(round(ytm*100,2))
|
916
|
-
ymax=df[mtype]
|
917
|
-
ymin=min(df[mtype])
|
918
|
-
plt.vlines(x=xpos,ymin=ymin,ymax=p0,ls=":",colors="blue")
|
919
|
-
|
920
|
-
titletxt="债券的利率风险:市场利率(到期收益率)的影响"
|
921
|
-
footnote1='市场利率%'
|
922
|
-
|
923
|
-
# 改变风险因素4:年付息次数
|
924
|
-
if change_type == 'coupon_times':
|
925
|
-
factor_list=[]
|
926
|
-
for f in coupon_times_list:
|
927
|
-
f1=f
|
928
|
-
if f1 <= 0: continue
|
929
|
-
factor_list=factor_list + [f1]
|
930
|
-
|
931
|
-
for f1 in factor_list:
|
932
|
-
p1=calc_macaulay(coupon_rate=coupon_rate,maturity_years=maturity_years, \
|
933
|
-
ytm=ytm,coupon_times=f1,par_value=par_value, \
|
934
|
-
mtype=mtype,rate_change=0)
|
935
|
-
s=pd.Series({'coupon_rate':coupon_rate,'maturity_years':maturity_years, \
|
936
|
-
'ytm':ytm,'coupon_times':f1,'par_value':par_value, \
|
937
|
-
mtype:p1})
|
938
|
-
try:
|
939
|
-
df=df.append(s, ignore_index=True)
|
940
|
-
except:
|
941
|
-
df=df._append(s, ignore_index=True)
|
942
|
-
|
943
|
-
#按照升序排序
|
944
|
-
df.sort_values(by=[change_type],ascending=[True],inplace=True)
|
945
|
-
#指定索引
|
946
|
-
df.reset_index(drop=True,inplace=True)
|
947
|
-
|
948
|
-
# 变化百分比:限coupon_rate和ytm
|
949
|
-
df['coupon_rate%']=df['coupon_rate'].apply(lambda x:round(x*100,2))
|
950
|
-
df['ytm%']=df['ytm'].apply(lambda x:round(x*100,2))
|
951
|
-
|
952
|
-
# 绘图,横轴数值转换为字符串,以便逐点显示
|
953
|
-
df['coupon_times_str']=df['coupon_times'].astype(str)
|
954
|
-
plt.plot(df['coupon_times_str'],df[mtype],color='red',marker='o')
|
955
|
-
|
956
|
-
# 绘制竖线
|
957
|
-
xpos=str(coupon_times)+'.0' #为匹配字符串形式的年数
|
958
|
-
ymax=df[mtype]
|
959
|
-
ymin=min(df[mtype])
|
960
|
-
plt.vlines(x=xpos,ymin=ymin,ymax=p0,ls=":",colors="blue")
|
961
|
-
|
962
|
-
titletxt="债券的利率风险:年付息次数变化的影响"
|
963
|
-
footnote1='年付息次数'
|
964
|
-
|
965
|
-
|
966
|
-
# 绘图标题和脚注
|
967
|
-
mtype_list_cn=['麦考利久期','修正久期','美元久期','有效久期','封闭久期','凸度']
|
968
|
-
mpos=mtype_list.index(mtype)
|
969
|
-
ylabel_txt=mtype_list_cn[mpos]
|
970
|
-
|
971
|
-
plt.ylabel(ylabel_txt,fontsize=ylabel_txt_size)
|
972
|
-
footnote2="\n"+"债券面值"+str(par_value)+",票面利率"+str(round(coupon_rate*100,2))+"%,"
|
973
|
-
footnote3="每年付息次数"+str(coupon_times)+",到期年数"+str(maturity_years)
|
974
|
-
footnote4=",到期收益率"+str(round(ytm*100,2))+"%"
|
975
|
-
|
976
|
-
footnote=footnote1+footnote2+footnote3+footnote4
|
977
|
-
plt.title(titletxt,fontsize=title_txt_size,fontweight='bold')
|
978
|
-
plt.xlabel(footnote,fontsize=xlabel_txt_size)
|
979
|
-
plt.xticks(rotation=30)
|
980
|
-
|
981
|
-
plt.gca().set_facecolor('whitesmoke')
|
982
|
-
plt.show(); plt.close()
|
983
|
-
|
984
|
-
return df
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
#==============================================================================
|
989
|
-
#==============================================================================
|
990
|
-
#==============================================================================
|
991
|
-
|
992
|
-
|