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,1925 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
"""
|
3
|
-
本模块功能:期权定价理论计算函数包
|
4
|
-
所属工具包:证券投资分析工具SIAT
|
5
|
-
SIAT:Security Investment Analysis Tool
|
6
|
-
创建日期:2020年7月16日
|
7
|
-
最新修订日期:2020年8月5日
|
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.grafix import *
|
21
|
-
from siat.security_prices import *
|
22
|
-
from siat.security_trend2 import *
|
23
|
-
from siat.yf_name import *
|
24
|
-
#==============================================================================
|
25
|
-
import matplotlib.pyplot as plt
|
26
|
-
|
27
|
-
#处理绘图汉字乱码问题
|
28
|
-
import sys; czxt=sys.platform
|
29
|
-
if czxt in ['win32','win64']:
|
30
|
-
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置默认字体
|
31
|
-
mpfrc={'font.family': 'SimHei'}
|
32
|
-
|
33
|
-
if czxt in ['darwin']: #MacOSX
|
34
|
-
plt.rcParams['font.family']= ['Heiti TC']
|
35
|
-
mpfrc={'font.family': 'Heiti TC'}
|
36
|
-
|
37
|
-
if czxt in ['linux']: #website Jupyter
|
38
|
-
plt.rcParams['font.family']= ['Heiti TC']
|
39
|
-
mpfrc={'font.family':'Heiti TC'}
|
40
|
-
|
41
|
-
# 解决保存图像时'-'显示为方块的问题
|
42
|
-
plt.rcParams['axes.unicode_minus'] = False
|
43
|
-
|
44
|
-
#==============================================================================
|
45
|
-
if __name__=='__main__':
|
46
|
-
direction='call'
|
47
|
-
|
48
|
-
|
49
|
-
def bs_pricing(S0,X,Days,r0,sigma,direction='call',printout=True):
|
50
|
-
"""
|
51
|
-
功能:计算无红利支付的欧式期权B-S定价模型,默认看涨期权
|
52
|
-
注意:
|
53
|
-
S0:标的物资产的当前价格,X为其行权价
|
54
|
-
sigma:标的物资产价格收益率的年化标准差
|
55
|
-
r0:年化无风险利率(程序中会转化为连续计算的无风险利率)
|
56
|
-
Days:距离到期日的天数(程序中会转换为距离到期日的年数=距离到期日的天数/365)
|
57
|
-
"""
|
58
|
-
|
59
|
-
direction=direction.upper()
|
60
|
-
|
61
|
-
if direction=='CALL':
|
62
|
-
C0=bs_call(S0,X,Days,r0,sigma,printout=printout)
|
63
|
-
else:
|
64
|
-
C0=bs_put(S0,X,Days,r0,sigma,printout=printout)
|
65
|
-
|
66
|
-
|
67
|
-
return C0
|
68
|
-
|
69
|
-
#==============================================================================
|
70
|
-
|
71
|
-
def bs_call(S0,X,Days,r0,sigma,printout=True):
|
72
|
-
"""
|
73
|
-
功能:计算无红利支付的欧式期权B-S定价模型,看涨期权
|
74
|
-
注意:
|
75
|
-
S0:标的物资产的当前价格,X为其行权价
|
76
|
-
sigma:标的物资产价格收益率的年化标准差
|
77
|
-
r0:年化无风险利率(需要转化为连续计算的无风险利率)
|
78
|
-
Days:距离到期日的天数,需要转换为距离到期日的年数=距离到期日的天数/365
|
79
|
-
"""
|
80
|
-
from scipy import stats
|
81
|
-
from numpy import log,exp,sqrt
|
82
|
-
|
83
|
-
#Days为距离到期日的日历日天数
|
84
|
-
T=Days/365.
|
85
|
-
r=log(r0+1)
|
86
|
-
|
87
|
-
d1=(log(S0/X)+(r+sigma*sigma/2.)*T)/(sigma*sqrt(T))
|
88
|
-
d2=d1-sigma*sqrt(T)
|
89
|
-
|
90
|
-
C0=S0*stats.norm.cdf(d1)-X*exp(-r*T)*stats.norm.cdf(d2)
|
91
|
-
|
92
|
-
if not printout: return C0
|
93
|
-
print("\n===== Black-Scholes期权定价 =====")
|
94
|
-
print("适用情形: 欧式期权,标的资产无红利收益")
|
95
|
-
print("标的资产行权价:",X)
|
96
|
-
print("标的资产现价 :",S0)
|
97
|
-
print("标的资产的年化波动率:",round(sigma,4))
|
98
|
-
print("距离到期日的年数 :",round(T,4))
|
99
|
-
print("连续计算的无风险利率:",round(r*100,4),'\b%')
|
100
|
-
print("看涨期权的预期价格 :",round(C0,4))
|
101
|
-
|
102
|
-
return C0
|
103
|
-
|
104
|
-
if __name__=='__main__':
|
105
|
-
S0=40
|
106
|
-
X=42
|
107
|
-
Days=183
|
108
|
-
r0=0.03
|
109
|
-
sigma=0.02
|
110
|
-
C0=bs_call(40,42,183,0.015,0.02)
|
111
|
-
|
112
|
-
#==============================================================================
|
113
|
-
def bsm_call(S0,X,Days,r0,sigma,Days1=0,div1=0,printout=True):
|
114
|
-
"""
|
115
|
-
功能:计算有红利支付的欧式期权B-S定价模型,看涨期权
|
116
|
-
注意:
|
117
|
-
S0:标的物资产的当前价格,X为其行权价
|
118
|
-
sigma:标的物资产价格收益率的年化标准差
|
119
|
-
r0:年化无风险利率(需要转化为连续计算的无风险利率)
|
120
|
-
Days:距离到期日的天数,需要转换为距离到期日的年数=距离到期日的天数/365
|
121
|
-
Days1:红利发放时距离到期日的天数,需要转换为年数
|
122
|
-
div1:红利金额
|
123
|
-
"""
|
124
|
-
from numpy import log,exp
|
125
|
-
#Days1为距离到期日的日历日天数
|
126
|
-
T=Days/365.
|
127
|
-
T1=Days1/365.
|
128
|
-
r=log(r0+1)
|
129
|
-
#调整标的物当前价
|
130
|
-
S=S0-exp(-r*T1)*div1
|
131
|
-
|
132
|
-
#调用BS模型计算
|
133
|
-
C=bs_call(S,X,Days,r0,sigma,printout=False)
|
134
|
-
|
135
|
-
if not printout: return C
|
136
|
-
print("\n=== Black-Scholes-Merton期权定价 ===")
|
137
|
-
print("适用情形: 欧式期权,标的资产有红利收益")
|
138
|
-
print("标的资产行权价:",X)
|
139
|
-
print("标的资产现价 :",S0)
|
140
|
-
print("标的资产的年化波动率 :",round(sigma,4))
|
141
|
-
print("距离到期日的年数 :",round(T,4))
|
142
|
-
print("连续计算的无风险利率 :",round(r,4)*100,'\b%')
|
143
|
-
print("红利及距离到期日的年数:",div1,"@",round(T1,4))
|
144
|
-
print("看涨期权的预期价格 :",round(C,4))
|
145
|
-
|
146
|
-
return C
|
147
|
-
|
148
|
-
if __name__=='__main__':
|
149
|
-
S0=42
|
150
|
-
X=40
|
151
|
-
Days=183
|
152
|
-
r0=0.03
|
153
|
-
sigma=0.02
|
154
|
-
dv1=1.5
|
155
|
-
Days1=183
|
156
|
-
C=bsm_call(42,40,183,0.015,0.02,183,1.5)
|
157
|
-
C0=bsm_call(42,40,183,0.015,0.23)
|
158
|
-
|
159
|
-
#==============================================================================
|
160
|
-
def bs_put(S0,X,Days,r0,sigma,printout=True):
|
161
|
-
"""
|
162
|
-
功能:计算无红利支付的欧式期权B-S定价模型,看跌期权
|
163
|
-
注意:
|
164
|
-
S0:标的物资产的当前价格,X为其行权价
|
165
|
-
sigma:标的物资产价格收益率的年化标准差
|
166
|
-
r0:年化无风险利率(需要转化为连续计算的无风险利率)
|
167
|
-
Days:距离到期日的天数,需要转换为距离到期日的年数=距离到期日的天数/365
|
168
|
-
"""
|
169
|
-
from scipy import stats
|
170
|
-
from numpy import log,exp,sqrt
|
171
|
-
|
172
|
-
#Days为距离到期日的日历日天数
|
173
|
-
T=Days/365.
|
174
|
-
r=log(r0+1)
|
175
|
-
|
176
|
-
d1=(log(S0/X)+(r+sigma*sigma/2.)*T)/(sigma*sqrt(T))
|
177
|
-
d2=d1-sigma*sqrt(T)
|
178
|
-
|
179
|
-
P0=-S0*stats.norm.cdf(-d1)+X*exp(-r*T)*stats.norm.cdf(-d2)
|
180
|
-
|
181
|
-
if not printout: return P0
|
182
|
-
print("\n===== Black-Scholes期权定价 =====")
|
183
|
-
print("适用情形: 欧式期权,标的资产无红利收益")
|
184
|
-
print("标的资产行权价:",X)
|
185
|
-
print("标的资产现价 :",S0)
|
186
|
-
print("标的资产的年化波动率:",round(sigma,4))
|
187
|
-
print("距离到期日的年数 :",round(T,4))
|
188
|
-
print("连续计算的无风险利率:",round(r*100,4),'\b%')
|
189
|
-
print("看跌期权的预期价格 :",round(P0,4))
|
190
|
-
|
191
|
-
return P0
|
192
|
-
|
193
|
-
if __name__=='__main__':
|
194
|
-
S0=40
|
195
|
-
X=42
|
196
|
-
Days=183
|
197
|
-
r0=0.03
|
198
|
-
sigma=0.02
|
199
|
-
P0=bs_put(40,42,183,0.015,0.02)
|
200
|
-
|
201
|
-
#==============================================================================
|
202
|
-
def bsm_put(S0,X,Days,r0,sigma,Days1=0,div1=0,printout=True):
|
203
|
-
"""
|
204
|
-
功能:计算有红利支付的欧式期权B-S定价模型,看跌期权
|
205
|
-
注意:
|
206
|
-
S0:标的物资产的当前价格,X为其行权价
|
207
|
-
sigma:标的物资产价格收益率的年化标准差
|
208
|
-
r0:年化无风险利率(需要转化为连续计算的无风险利率)
|
209
|
-
Days:距离到期日的天数,需要转换为距离到期日的年数=距离到期日的天数/365
|
210
|
-
Days1:红利发放时距离到期日的天数,需要转换为年数
|
211
|
-
div1:红利金额
|
212
|
-
"""
|
213
|
-
from numpy import log,exp,sqrt
|
214
|
-
|
215
|
-
#Days为距离到期日的日历日天数
|
216
|
-
T=Days/365.
|
217
|
-
T1=Days1/365.
|
218
|
-
r=log(r0+1)
|
219
|
-
|
220
|
-
S=S0-exp(-r*T1)*div1
|
221
|
-
|
222
|
-
#调用BS模型计算
|
223
|
-
P=bs_put(S,X,Days,r0,sigma,printout=False)
|
224
|
-
|
225
|
-
if not printout: return P
|
226
|
-
print("\n=== Black-Scholes-Merton期权定价 ===")
|
227
|
-
print("适用情形: 欧式期权,标的资产有红利收益")
|
228
|
-
print("标的资产行权价:",X)
|
229
|
-
print("标的资产现价 :",S0)
|
230
|
-
print("标的资产的年化波动率 :",round(sigma,4))
|
231
|
-
print("距离到期日的年数 :",round(T,4))
|
232
|
-
print("连续计算的无风险利率 :",round(r,4)*100,'\b%')
|
233
|
-
print("红利及距离到期日的年数:",div1,"@",round(T1,2))
|
234
|
-
print("看跌期权的预期价格 :",round(P,4))
|
235
|
-
|
236
|
-
return P
|
237
|
-
|
238
|
-
if __name__=='__main__':
|
239
|
-
S0=42
|
240
|
-
X=40
|
241
|
-
Days=183
|
242
|
-
r0=0.03
|
243
|
-
sigma=0.02
|
244
|
-
P=bsm_put(42,40,183,0.015,0.23,90,1.5)
|
245
|
-
P0=bsm_put(42,40,183,0.015,0.23)
|
246
|
-
|
247
|
-
#==============================================================================
|
248
|
-
def bsm_put_aprice(Srange,X,Days,r0,sigma,Days1=0,div1=0,graph=True):
|
249
|
-
"""
|
250
|
-
功能:计算有红利支付的欧式期权BSM定价模型,看跌期权,当前价格为变化范围
|
251
|
-
注意:
|
252
|
-
Srange:标的物资产的当前价格范围,默认20等分后作为横轴绘图
|
253
|
-
X:期权的行权价
|
254
|
-
sigma:标的物资产价格收益率的年化标准差
|
255
|
-
r0:年化无风险利率(需要转化为连续计算的无风险利率)
|
256
|
-
Days:距离到期日的天数,需要转换为距离到期日的年数=距离到期日的天数/365
|
257
|
-
Days1:红利发放时距离到期日的天数,需要转换为年数
|
258
|
-
div1:红利金额
|
259
|
-
"""
|
260
|
-
#通用修改点
|
261
|
-
trange=Srange
|
262
|
-
#检查是否为列表
|
263
|
-
if not isinstance(trange,list):
|
264
|
-
print("#Error(bsm_put_aprice): target is not a range,",trange)
|
265
|
-
return
|
266
|
-
if len(trange) < 2:
|
267
|
-
print("#Error(bsm_put_aprice): not enough range for target,",trange)
|
268
|
-
return
|
269
|
-
|
270
|
-
#确定起始位置和间隔大小
|
271
|
-
tstart=trange[0]; tend=trange[1]
|
272
|
-
if len(trange) >=3: tstep=trange[2]
|
273
|
-
else: tstep=(tend-tstart)/20.
|
274
|
-
#横轴点列表
|
275
|
-
import numpy as np
|
276
|
-
tlist=np.arange(tstart,tend+tstep,tstep)
|
277
|
-
|
278
|
-
#循环计算各点数值
|
279
|
-
import pandas as pd
|
280
|
-
df=pd.DataFrame(columns=['Option Price','Asset Price','Strike Price', \
|
281
|
-
'Days to Maturity','Annual RF', \
|
282
|
-
'Annual Sigma','Div to Maturity','Dividend'])
|
283
|
-
for t in tlist:
|
284
|
-
#通用修改点
|
285
|
-
op=bsm_put(t,X,Days,r0,sigma,Days1,div1,printout=False)
|
286
|
-
s=pd.Series({'Option Price':op,'Asset Price':t,'Strike Price':X, \
|
287
|
-
'Days to Maturity':Days,'Annual RF':r0, \
|
288
|
-
'Annual Sigma':sigma,'Div to Maturity':Days1, \
|
289
|
-
'Dividend':div1})
|
290
|
-
try:
|
291
|
-
df=df.append(s,ignore_index=True)
|
292
|
-
except:
|
293
|
-
df=df._append(s,ignore_index=True)
|
294
|
-
#通用修改点
|
295
|
-
df2=df.set_index(['Asset Price'])
|
296
|
-
if not graph: return df2
|
297
|
-
|
298
|
-
#绘图
|
299
|
-
#通用修改点
|
300
|
-
colname='Option Price'; collabel='看跌期权'
|
301
|
-
ylabeltxt='期权价格'
|
302
|
-
titletxt='期权价格的变化趋势图'
|
303
|
-
#通用修改点
|
304
|
-
fn1='标的物市场价格'
|
305
|
-
fn2='\n[期权信息]行权价='+str(X)+', 距离到期天数='+str(Days)
|
306
|
-
fn3='\n年化无风险利率%='+str(round(r0*100.,2))+', 年化波动率%='+str(round(sigma*100.,2))
|
307
|
-
if div1==0:
|
308
|
-
fn4='\n本产品无红利收益'
|
309
|
-
else:
|
310
|
-
fn4='\n发放红利时间距离到期天数='+str(Days1)+', 红利='+str(div1)
|
311
|
-
footnote=fn1+fn2+fn3+fn4
|
312
|
-
plot_line(df2,colname,collabel,ylabeltxt,titletxt,footnote)
|
313
|
-
|
314
|
-
return df2
|
315
|
-
|
316
|
-
if __name__=='__main__':
|
317
|
-
Srange=[30,50,1]
|
318
|
-
X=40
|
319
|
-
Days=183
|
320
|
-
r0=0.03
|
321
|
-
sigma=0.02
|
322
|
-
Days1=0
|
323
|
-
div1=0
|
324
|
-
pdf=bsm_put_aprice(Srange,40,183,0.015,0.23,90,1.5)
|
325
|
-
|
326
|
-
#==============================================================================
|
327
|
-
def bsm_call_aprice(Srange,X,Days,r0,sigma,Days1=0,div1=0,graph=True):
|
328
|
-
"""
|
329
|
-
功能:计算有红利支付的欧式期权BSM定价模型,看涨期权,当前价格为变化范围
|
330
|
-
注意:
|
331
|
-
Srange:标的物资产的当前价格范围,默认20等分后作为横轴绘图
|
332
|
-
X:期权的行权价
|
333
|
-
sigma:标的物资产价格收益率的年化标准差
|
334
|
-
r0:年化无风险利率(需要转化为连续计算的无风险利率)
|
335
|
-
Days:距离到期日的天数,需要转换为距离到期日的年数=距离到期日的天数/365
|
336
|
-
Days1:红利发放时距离到期日的天数,需要转换为年数
|
337
|
-
div1:红利金额
|
338
|
-
"""
|
339
|
-
#通用修改点
|
340
|
-
trange=Srange
|
341
|
-
#检查是否为列表
|
342
|
-
if not isinstance(trange,list):
|
343
|
-
print("#Error(bsm_call_aprice): target is not a range,",trange)
|
344
|
-
return
|
345
|
-
if len(trange) < 2:
|
346
|
-
print("#Error(bsm_call_aprice): not enough range for target,",trange)
|
347
|
-
return
|
348
|
-
|
349
|
-
#确定起始位置和间隔大小
|
350
|
-
tstart=trange[0]; tend=trange[1]
|
351
|
-
if len(trange) >=3: tstep=trange[2]
|
352
|
-
else: tstep=(tend-tstart)/20.
|
353
|
-
#横轴点列表
|
354
|
-
import numpy as np
|
355
|
-
tlist=np.arange(tstart,tend+tstep,tstep)
|
356
|
-
|
357
|
-
#循环计算各点数值
|
358
|
-
import pandas as pd
|
359
|
-
df=pd.DataFrame(columns=['Option Price','Asset Price','Strike Price', \
|
360
|
-
'Days to Maturity','Annual RF', \
|
361
|
-
'Annual Sigma','Div to Maturity','Dividend'])
|
362
|
-
for t in tlist:
|
363
|
-
#通用修改点
|
364
|
-
op=bsm_call(t,X,Days,r0,sigma,Days1,div1,printout=False)
|
365
|
-
s=pd.Series({'Option Price':op,'Asset Price':t,'Strike Price':X, \
|
366
|
-
'Days to Maturity':Days,'Annual RF':r0, \
|
367
|
-
'Annual Sigma':sigma,'Div to Maturity':Days1, \
|
368
|
-
'Dividend':div1})
|
369
|
-
try:
|
370
|
-
df=df.append(s,ignore_index=True)
|
371
|
-
except:
|
372
|
-
df=df._append(s,ignore_index=True)
|
373
|
-
#通用修改点
|
374
|
-
df2=df.set_index(['Asset Price'])
|
375
|
-
if not graph: return df2
|
376
|
-
|
377
|
-
#绘图
|
378
|
-
#通用修改点
|
379
|
-
colname='Option Price'; collabel='看涨期权'
|
380
|
-
ylabeltxt='期权价格'
|
381
|
-
titletxt='期权价格的变化趋势图'
|
382
|
-
#通用修改点
|
383
|
-
fn1='标的物市场价格'
|
384
|
-
fn2='\n[期权信息]行权价='+str(X)+', 距离到期天数='+str(Days)
|
385
|
-
fn3='\n年化无风险利率%='+str(round(r0*100.,2))+', 年化波动率%='+str(round(sigma*100.,2))
|
386
|
-
if div1==0:
|
387
|
-
fn4='\n本产品无红利收益'
|
388
|
-
else:
|
389
|
-
fn4='\n发放红利时间距离到期天数='+str(Days1)+', 红利='+str(div1)
|
390
|
-
footnote=fn1+fn2+fn3+fn4
|
391
|
-
plot_line(df2,colname,collabel,ylabeltxt,titletxt,footnote)
|
392
|
-
|
393
|
-
return df2
|
394
|
-
|
395
|
-
if __name__=='__main__':
|
396
|
-
Srange=[30,50,1]
|
397
|
-
X=40
|
398
|
-
Days=183
|
399
|
-
r0=0.03
|
400
|
-
sigma=0.02
|
401
|
-
Days1=0
|
402
|
-
div1=0
|
403
|
-
cdf=bsm_call_aprice(Srange,40,183,0.015,0.23,90,1.5)
|
404
|
-
|
405
|
-
#==============================================================================
|
406
|
-
def bsm_aprice(Srange,X,Days,r0,sigma,Days1=0,div1=0,graph=True):
|
407
|
-
"""
|
408
|
-
功能:计算有红利支付的欧式期权BSM定价模型,看涨/看跌期权,当前价格为变化范围
|
409
|
-
注意:
|
410
|
-
Srange:标的物资产的当前价格范围,默认20等分后作为横轴绘图
|
411
|
-
X:期权的行权价
|
412
|
-
sigma:标的物资产价格收益率的年化标准差
|
413
|
-
r0:年化无风险利率(需要转化为连续计算的无风险利率)
|
414
|
-
Days:距离到期日的天数,需要转换为距离到期日的年数=距离到期日的天数/365
|
415
|
-
Days1:红利发放时距离到期日的天数,需要转换为年数
|
416
|
-
div1:红利金额
|
417
|
-
"""
|
418
|
-
#通用修改点
|
419
|
-
trange=Srange
|
420
|
-
#检查是否为列表
|
421
|
-
if not isinstance(trange,list):
|
422
|
-
print("#Error(bsm_aprice): target is not a range,",trange)
|
423
|
-
return
|
424
|
-
if len(trange) < 2:
|
425
|
-
print("#Error(bsm_aprice): not enough range for target,",trange)
|
426
|
-
return
|
427
|
-
|
428
|
-
#看涨期权
|
429
|
-
df1=bsm_call_aprice(Srange,X,Days,r0,sigma,Days1=0,div1=0,graph=False)
|
430
|
-
#看跌期权
|
431
|
-
df2=bsm_put_aprice(Srange,X,Days,r0,sigma,Days1=0,div1=0,graph=False)
|
432
|
-
|
433
|
-
#绘图
|
434
|
-
#通用修改点
|
435
|
-
ticker1='看涨期权'; colname1='Option Price'; label1='期权-C-'+str(X)
|
436
|
-
ticker2='看跌期权'; colname2='Option Price'; label2='期权-P-'+str(X)
|
437
|
-
ylabeltxt='期权价格'
|
438
|
-
titletxt='期权价格的变化趋势图'
|
439
|
-
#通用修改点
|
440
|
-
fn1='标的物市场价格-->'
|
441
|
-
fn2='\n[期权信息]行权价='+str(X)+', 距离到期天数='+str(Days)
|
442
|
-
fn3='\n年化无风险利率%='+str(round(r0*100.,2))+', 年化波动率%='+str(round(sigma*100.,2))
|
443
|
-
if div1==0:
|
444
|
-
fn4='\n本产品无红利收益'
|
445
|
-
else:
|
446
|
-
fn4='\n发放红利时间距离到期天数='+str(Days1)+', 红利='+str(div1)
|
447
|
-
footnote=fn1+fn2+fn3+fn4
|
448
|
-
plot_line2_coaxial(df1,ticker1,colname1,label1, \
|
449
|
-
df2,ticker2,colname2,label2, \
|
450
|
-
ylabeltxt,titletxt,footnote)
|
451
|
-
return
|
452
|
-
|
453
|
-
if __name__=='__main__':
|
454
|
-
Srange=[30,50,1]
|
455
|
-
X=40
|
456
|
-
Days=183
|
457
|
-
r0=0.03
|
458
|
-
sigma=0.02
|
459
|
-
Days1=0
|
460
|
-
div1=0
|
461
|
-
bsm_aprice(Srange,40,183,0.015,0.23,90,1.5)
|
462
|
-
bsm_aprice([30,50],40,183,0.015,0.23,90,1.5)
|
463
|
-
|
464
|
-
#==============================================================================
|
465
|
-
def bsm_put_maturity(S0,X,Dayrange,r0,sigma,Days1=0,div1=0,graph=True):
|
466
|
-
"""
|
467
|
-
功能:计算有红利支付的欧式期权BSM定价模型,看跌期权,距离到期日天数为变化范围
|
468
|
-
注意:
|
469
|
-
S0:标的物资产的当前价格
|
470
|
-
X:期权的行权价
|
471
|
-
sigma:标的物资产价格收益率的年化标准差
|
472
|
-
r0:年化无风险利率(需要转化为连续计算的无风险利率)
|
473
|
-
Dayrange:距离到期日的天数范围,默认变化间隔为20分之一取整
|
474
|
-
Days1:红利发放时距离到期日的天数,需要转换为年数
|
475
|
-
div1:红利金额
|
476
|
-
"""
|
477
|
-
#通用修改点
|
478
|
-
trange=Dayrange
|
479
|
-
#检查是否为列表
|
480
|
-
if not isinstance(trange,list):
|
481
|
-
print("#Error(bsm_put_maturity): target is not a range,",trange)
|
482
|
-
return
|
483
|
-
if len(trange) < 2:
|
484
|
-
print("#Error(bsm_put_maturity): not enough range for target,",trange)
|
485
|
-
return
|
486
|
-
|
487
|
-
#确定起始位置和间隔大小
|
488
|
-
tstart=int(trange[0]); tend=int(trange[1])
|
489
|
-
if len(trange) >=3: tstep=trange[2]
|
490
|
-
else: tstep=int((tend-tstart)/20)
|
491
|
-
#横轴点列表
|
492
|
-
#import numpy as np
|
493
|
-
tlist=range(tstart,tend+tstep,tstep)
|
494
|
-
|
495
|
-
#循环计算各点数值
|
496
|
-
import pandas as pd
|
497
|
-
df=pd.DataFrame(columns=['Option Price','Asset Price','Strike Price', \
|
498
|
-
'Days to Maturity','Annual RF', \
|
499
|
-
'Annual Sigma','Div to Maturity','Dividend'])
|
500
|
-
for t in tlist:
|
501
|
-
#通用修改点
|
502
|
-
op=bsm_put(S0,X,t,r0,sigma,Days1,div1,printout=False)
|
503
|
-
s=pd.Series({'Option Price':op,'Asset Price':S0,'Strike Price':X, \
|
504
|
-
'Days to Maturity':t,'Annual RF':r0, \
|
505
|
-
'Annual Sigma':sigma,'Div to Maturity':Days1, \
|
506
|
-
'Dividend':div1})
|
507
|
-
try:
|
508
|
-
df=df.append(s,ignore_index=True)
|
509
|
-
except:
|
510
|
-
df=df._append(s,ignore_index=True)
|
511
|
-
#通用修改点
|
512
|
-
df2=df.set_index(['Days to Maturity'])
|
513
|
-
if not graph: return df2
|
514
|
-
|
515
|
-
#绘图
|
516
|
-
#通用修改点
|
517
|
-
colname='Option Price'; collabel='看跌期权'
|
518
|
-
ylabeltxt='期权价格'
|
519
|
-
titletxt='期权价格的变化趋势图'
|
520
|
-
#通用修改点
|
521
|
-
fn1='<--距离到期日的天数'
|
522
|
-
fn2='\n[期权信息]行权价='+str(X)+', 标的物市价='+str(S0)
|
523
|
-
fn3='\n年化无风险利率%='+str(round(r0*100.,2))+', 年化波动率%='+str(round(sigma*100.,2))
|
524
|
-
if div1==0:
|
525
|
-
fn4='\n本产品无红利收益'
|
526
|
-
else:
|
527
|
-
fn4='\n发放红利时间距离到期天数='+str(Days1)+', 红利='+str(div1)
|
528
|
-
footnote=fn1+fn2+fn3+fn4
|
529
|
-
plot_line(df2,colname,collabel,ylabeltxt,titletxt,footnote)
|
530
|
-
|
531
|
-
return df2
|
532
|
-
|
533
|
-
if __name__=='__main__':
|
534
|
-
S0=42
|
535
|
-
X=40
|
536
|
-
Dayrange=[200,50]
|
537
|
-
r0=0.015
|
538
|
-
sigma=0.23
|
539
|
-
Days1=90
|
540
|
-
div1=1.5
|
541
|
-
pdf=bsm_put_maturity(42,40,[200,50],0.015,0.23,90,1.5)
|
542
|
-
|
543
|
-
#==============================================================================
|
544
|
-
def bsm_call_maturity(S0,X,Dayrange,r0,sigma,Days1=0,div1=0,graph=True):
|
545
|
-
"""
|
546
|
-
功能:计算有红利支付的欧式期权BSM定价模型,看涨期权,距离到期日天数为变化范围
|
547
|
-
注意:
|
548
|
-
S0:标的物资产的当前价格
|
549
|
-
X:期权的行权价
|
550
|
-
sigma:标的物资产价格收益率的年化标准差
|
551
|
-
r0:年化无风险利率(需要转化为连续计算的无风险利率)
|
552
|
-
Dayrange:距离到期日的天数范围,默认变化间隔为20分之一取整
|
553
|
-
Days1:红利发放时距离到期日的天数,需要转换为年数
|
554
|
-
div1:红利金额
|
555
|
-
"""
|
556
|
-
#通用修改点
|
557
|
-
trange=Dayrange
|
558
|
-
#检查是否为列表
|
559
|
-
if not isinstance(trange,list):
|
560
|
-
print("#Error(bsm_call_maturity): target is not a range,",trange)
|
561
|
-
return
|
562
|
-
if len(trange) < 2:
|
563
|
-
print("#Error(bsm_call_maturity): not enough range for target,",trange)
|
564
|
-
return
|
565
|
-
|
566
|
-
#确定起始位置和间隔大小
|
567
|
-
tstart=int(trange[0]); tend=int(trange[1])
|
568
|
-
if len(trange) >=3: tstep=trange[2]
|
569
|
-
else: tstep=int((tend-tstart)/20)
|
570
|
-
#横轴点列表
|
571
|
-
#import numpy as np
|
572
|
-
tlist=range(tstart,tend+tstep,tstep)
|
573
|
-
|
574
|
-
#循环计算各点数值
|
575
|
-
import pandas as pd
|
576
|
-
df=pd.DataFrame(columns=['Option Price','Asset Price','Strike Price', \
|
577
|
-
'Days to Maturity','Annual RF', \
|
578
|
-
'Annual Sigma','Div to Maturity','Dividend'])
|
579
|
-
for t in tlist:
|
580
|
-
#通用修改点
|
581
|
-
op=bsm_call(S0,X,t,r0,sigma,Days1,div1,printout=False)
|
582
|
-
s=pd.Series({'Option Price':op,'Asset Price':S0,'Strike Price':X, \
|
583
|
-
'Days to Maturity':t,'Annual RF':r0, \
|
584
|
-
'Annual Sigma':sigma,'Div to Maturity':Days1, \
|
585
|
-
'Dividend':div1})
|
586
|
-
try:
|
587
|
-
df=df.append(s,ignore_index=True)
|
588
|
-
except:
|
589
|
-
df=df._append(s,ignore_index=True)
|
590
|
-
#通用修改点
|
591
|
-
df2=df.set_index(['Days to Maturity'])
|
592
|
-
if not graph: return df2
|
593
|
-
|
594
|
-
#绘图
|
595
|
-
#通用修改点
|
596
|
-
colname='Option Price'; collabel='看涨期权'
|
597
|
-
ylabeltxt='期权价格'
|
598
|
-
titletxt='期权价格的变化趋势图'
|
599
|
-
#通用修改点
|
600
|
-
fn1='<--距离到期日的天数'
|
601
|
-
fn2='\n[期权信息]行权价='+str(X)+', 标的物市价='+str(S0)
|
602
|
-
fn3='\n年化无风险利率%='+str(round(r0*100.,2))+', 年化波动率%='+str(round(sigma*100.,2))
|
603
|
-
if div1==0:
|
604
|
-
fn4='\n本产品无红利收益'
|
605
|
-
else:
|
606
|
-
fn4='\n发放红利时间距离到期天数='+str(Days1)+', 红利='+str(div1)
|
607
|
-
footnote=fn1+fn2+fn3+fn4
|
608
|
-
plot_line(df2,colname,collabel,ylabeltxt,titletxt,footnote)
|
609
|
-
|
610
|
-
return df2
|
611
|
-
|
612
|
-
if __name__=='__main__':
|
613
|
-
S0=42
|
614
|
-
X=40
|
615
|
-
Dayrange=[200,50]
|
616
|
-
r0=0.015
|
617
|
-
sigma=0.23
|
618
|
-
Days1=90
|
619
|
-
div1=1.5
|
620
|
-
cdf=bsm_call_maturity(42,40,[200,50],0.015,0.23,90,1.5)
|
621
|
-
|
622
|
-
#==============================================================================
|
623
|
-
if __name__=='__main__':
|
624
|
-
S0=42
|
625
|
-
X=40
|
626
|
-
Dayrange=[200,50]
|
627
|
-
r0=0.015
|
628
|
-
sigma=0.23
|
629
|
-
Days1=90
|
630
|
-
div1=1.5
|
631
|
-
|
632
|
-
def bsm_maturity(S0,X,Dayrange,r0,sigma,Days1=0,div1=0,graph=True):
|
633
|
-
"""
|
634
|
-
功能:计算有红利支付的欧式期权BSM定价模型,看涨/看跌期权,距离到期日天数为变化范围
|
635
|
-
注意:
|
636
|
-
S0:标的物资产的当前价格
|
637
|
-
X:期权的行权价
|
638
|
-
sigma:标的物资产价格收益率的年化标准差
|
639
|
-
r0:年化无风险利率(需要转化为连续计算的无风险利率)
|
640
|
-
Dayrange:距离到期日的天数范围,默认间隔为20分之一取证
|
641
|
-
Days1:红利发放时距离到期日的天数,需要转换为年数
|
642
|
-
div1:红利金额
|
643
|
-
"""
|
644
|
-
#通用修改点
|
645
|
-
trange=Dayrange
|
646
|
-
#检查是否为列表
|
647
|
-
if not isinstance(trange,list):
|
648
|
-
print("#Error(bsm_maturity): target is not a range,",trange)
|
649
|
-
return
|
650
|
-
if len(trange) < 2:
|
651
|
-
print("#Error(bsm_maturity): not enough range for target,",trange)
|
652
|
-
return
|
653
|
-
|
654
|
-
#看涨期权
|
655
|
-
df1=bsm_call_maturity(S0,X,Dayrange,r0,sigma,Days1=0,div1=0,graph=False)
|
656
|
-
df1.sort_index(ascending=False, inplace=True)
|
657
|
-
#看跌期权
|
658
|
-
df2=bsm_put_maturity(S0,X,Dayrange,r0,sigma,Days1=0,div1=0,graph=False)
|
659
|
-
df2.sort_index(ascending=False, inplace=True)
|
660
|
-
#合并
|
661
|
-
import pandas as pd
|
662
|
-
df=pd.merge(df1,df2,how='inner',left_index=True,right_index=True,sort=True)
|
663
|
-
#df['到期日']=df.index
|
664
|
-
#df.sort_values('到期日',ascending=False,inplace=True)
|
665
|
-
|
666
|
-
#绘图
|
667
|
-
plt.title('期权价格的变化趋势图')
|
668
|
-
plt.ylabel('期权价格')
|
669
|
-
|
670
|
-
df['Option Price_x'].plot(label='看涨期权',ls='-')
|
671
|
-
df['Option Price_y'].plot(label='看跌期权',ls='-.')
|
672
|
-
|
673
|
-
fn1='距离到期日的天数-->'
|
674
|
-
fn2='\n[期权信息]行权价='+str(X)+', 标的物市价='+str(S0)
|
675
|
-
fn3='\n年化无风险利率%='+str(round(r0*100.,2))+', 年化波动率%='+str(round(sigma*100.,2))
|
676
|
-
if div1==0: fn4='\n本产品无红利收益'
|
677
|
-
else: fn4='\n发放红利时间距离到期天数='+str(Days1)+', 红利='+str(div1)
|
678
|
-
footnote=fn1+fn2+fn3+fn4
|
679
|
-
plt.xlabel(footnote)
|
680
|
-
|
681
|
-
#让横轴逆序从大到小显示,正常顺序为从小到大
|
682
|
-
plt.gca().invert_xaxis()
|
683
|
-
plt.legend()
|
684
|
-
|
685
|
-
plt.gca().set_facecolor('whitesmoke')
|
686
|
-
plt.show()
|
687
|
-
|
688
|
-
return
|
689
|
-
|
690
|
-
if __name__=='__main__':
|
691
|
-
S0=42
|
692
|
-
X=40
|
693
|
-
Dayrange=[200,50]
|
694
|
-
r0=0.015
|
695
|
-
sigma=0.23
|
696
|
-
Days1=90
|
697
|
-
div1=1.5
|
698
|
-
bsm_maturity(S0,40,[200,5],0.015,0.23,90,1.5)
|
699
|
-
bsm_maturity(42,40,[50,200],0.015,0.23,90,1.5)
|
700
|
-
|
701
|
-
#==============================================================================
|
702
|
-
def bsm_put_sigma(S0,X,Days,r0,sigmarange,Days1=0,div1=0,graph=True):
|
703
|
-
"""
|
704
|
-
功能:计算有红利支付的欧式期权BSM定价模型,看跌期权,年化波动率为变化范围
|
705
|
-
注意:
|
706
|
-
S0:标的物资产的当前价格
|
707
|
-
X:期权的行权价
|
708
|
-
sigmarange:标的物资产价格收益率的年化标准差范围,默认为区间的20分之一作为间隔
|
709
|
-
r0:年化无风险利率(需要转化为连续计算的无风险利率)
|
710
|
-
Days:距离到期日的天数
|
711
|
-
Days1:红利发放时距离到期日的天数,需要转换为年数
|
712
|
-
div1:红利金额
|
713
|
-
"""
|
714
|
-
#通用修改点
|
715
|
-
trange=sigmarange
|
716
|
-
#检查是否为列表
|
717
|
-
if not isinstance(trange,list):
|
718
|
-
print("#Error(bsm_put_sigma): target is not a range,",trange)
|
719
|
-
return
|
720
|
-
if len(trange) < 2:
|
721
|
-
print("#Error(bsm_put_sigma): not enough range for target,",trange)
|
722
|
-
return
|
723
|
-
|
724
|
-
#确定起始位置和间隔大小
|
725
|
-
tstart=trange[0]; tend=trange[1]
|
726
|
-
if len(trange) >=3: tstep=trange[2]
|
727
|
-
else: tstep=(tend-tstart)/20.
|
728
|
-
#横轴点列表
|
729
|
-
import numpy as np
|
730
|
-
tlist=np.arange(tstart,tend+tstep,tstep)
|
731
|
-
|
732
|
-
#循环计算各点数值
|
733
|
-
import pandas as pd
|
734
|
-
df=pd.DataFrame(columns=['Option Price','Asset Price','Strike Price', \
|
735
|
-
'Days to Maturity','Annual RF', \
|
736
|
-
'Annual Sigma','Div to Maturity','Dividend'])
|
737
|
-
for t in tlist:
|
738
|
-
#通用修改点
|
739
|
-
op=bsm_put(S0,X,Days,r0,t,Days1,div1,printout=False)
|
740
|
-
s=pd.Series({'Option Price':op,'Asset Price':S0,'Strike Price':X, \
|
741
|
-
'Days to Maturity':Days,'Annual RF':r0, \
|
742
|
-
'Annual Sigma':t,'Div to Maturity':Days1, \
|
743
|
-
'Dividend':div1})
|
744
|
-
try:
|
745
|
-
df=df.append(s,ignore_index=True)
|
746
|
-
except:
|
747
|
-
df=df._append(s,ignore_index=True)
|
748
|
-
#通用修改点
|
749
|
-
df2=df.set_index(['Annual Sigma'])
|
750
|
-
if not graph: return df2
|
751
|
-
|
752
|
-
#绘图
|
753
|
-
#通用修改点
|
754
|
-
colname='Option Price'; collabel='看跌期权'
|
755
|
-
ylabeltxt='期权价格'
|
756
|
-
titletxt='期权价格的变化趋势图'
|
757
|
-
#通用修改点
|
758
|
-
fn1='波动率-->'
|
759
|
-
fn2='\n[期权信息]行权价='+str(X)+', 标的物市价='+str(S0)
|
760
|
-
fn3='\n年化无风险利率%='+str(round(r0*100.,2))+', 距离到期日天数='+str(Days)
|
761
|
-
if div1==0:
|
762
|
-
fn4='\n本产品无红利收益'
|
763
|
-
else:
|
764
|
-
fn4='\n发放红利时间距离到期天数='+str(Days1)+', 红利='+str(div1)
|
765
|
-
footnote=fn1+fn2+fn3+fn4
|
766
|
-
plot_line(df2,colname,collabel,ylabeltxt,titletxt,footnote)
|
767
|
-
|
768
|
-
return df2
|
769
|
-
|
770
|
-
if __name__=='__main__':
|
771
|
-
S0=42
|
772
|
-
X=40
|
773
|
-
Days=183
|
774
|
-
r0=0.015
|
775
|
-
sigmarange=[0.1,0.4]
|
776
|
-
Days1=90
|
777
|
-
div1=1.5
|
778
|
-
pdf=bsm_put_sigma(42,40,183,0.015,[0.1,0.4],90,1.5)
|
779
|
-
|
780
|
-
|
781
|
-
#==============================================================================
|
782
|
-
def bsm_call_sigma(S0,X,Days,r0,sigmarange,Days1=0,div1=0,graph=True):
|
783
|
-
"""
|
784
|
-
功能:计算有红利支付的欧式期权BSM定价模型,看涨期权,年化波动率为变化范围
|
785
|
-
注意:
|
786
|
-
S0:标的物资产的当前价格
|
787
|
-
X:期权的行权价
|
788
|
-
sigmarange:标的物资产价格收益率的年化标准差范围,默认为区间的20分之一作为间隔
|
789
|
-
r0:年化无风险利率(需要转化为连续计算的无风险利率)
|
790
|
-
Days:距离到期日的天数
|
791
|
-
Days1:红利发放时距离到期日的天数,需要转换为年数
|
792
|
-
div1:红利金额
|
793
|
-
"""
|
794
|
-
#通用修改点
|
795
|
-
trange=sigmarange
|
796
|
-
#检查是否为列表
|
797
|
-
if not isinstance(trange,list):
|
798
|
-
print("#Error(bsm_call_sigma): target is not a range,",trange)
|
799
|
-
return
|
800
|
-
if len(trange) < 2:
|
801
|
-
print("#Error(bsm_call_sigma): not enough range for target,",trange)
|
802
|
-
return
|
803
|
-
|
804
|
-
#确定起始位置和间隔大小
|
805
|
-
tstart=trange[0]; tend=trange[1]
|
806
|
-
if len(trange) >=3: tstep=trange[2]
|
807
|
-
else: tstep=(tend-tstart)/20.
|
808
|
-
#横轴点列表
|
809
|
-
import numpy as np
|
810
|
-
tlist=np.arange(tstart,tend+tstep,tstep)
|
811
|
-
|
812
|
-
#循环计算各点数值
|
813
|
-
import pandas as pd
|
814
|
-
df=pd.DataFrame(columns=['Option Price','Asset Price','Strike Price', \
|
815
|
-
'Days to Maturity','Annual RF', \
|
816
|
-
'Annual Sigma','Div to Maturity','Dividend'])
|
817
|
-
for t in tlist:
|
818
|
-
#通用修改点
|
819
|
-
op=bsm_call(S0,X,Days,r0,t,Days1,div1,printout=False)
|
820
|
-
s=pd.Series({'Option Price':op,'Asset Price':S0,'Strike Price':X, \
|
821
|
-
'Days to Maturity':Days,'Annual RF':r0, \
|
822
|
-
'Annual Sigma':t,'Div to Maturity':Days1, \
|
823
|
-
'Dividend':div1})
|
824
|
-
try:
|
825
|
-
df=df.append(s,ignore_index=True)
|
826
|
-
except:
|
827
|
-
df=df._append(s,ignore_index=True)
|
828
|
-
#通用修改点
|
829
|
-
df2=df.set_index(['Annual Sigma'])
|
830
|
-
if not graph: return df2
|
831
|
-
|
832
|
-
#绘图
|
833
|
-
#通用修改点
|
834
|
-
colname='Option Price'; collabel='看涨期权'
|
835
|
-
ylabeltxt='期权价格'
|
836
|
-
titletxt='期权价格的变化趋势图'
|
837
|
-
#通用修改点
|
838
|
-
fn1='波动率-->'
|
839
|
-
fn2='\n[期权信息]行权价='+str(X)+', 标的物市价='+str(S0)
|
840
|
-
fn3='\n年化无风险利率%='+str(round(r0*100.,2))+', 距离到期日天数='+str(Days)
|
841
|
-
if div1==0:
|
842
|
-
fn4='\n本产品无红利收益'
|
843
|
-
else:
|
844
|
-
fn4='\n发放红利时间距离到期天数='+str(Days1)+', 红利='+str(div1)
|
845
|
-
footnote=fn1+fn2+fn3+fn4
|
846
|
-
plot_line(df2,colname,collabel,ylabeltxt,titletxt,footnote)
|
847
|
-
|
848
|
-
return df2
|
849
|
-
|
850
|
-
if __name__=='__main__':
|
851
|
-
S0=42
|
852
|
-
X=40
|
853
|
-
Days=183
|
854
|
-
r0=0.015
|
855
|
-
sigmarange=[0.1,0.4]
|
856
|
-
Days1=90
|
857
|
-
div1=1.5
|
858
|
-
cdf=bsm_call_sigma(42,40,183,0.015,[0.1,0.4],90,1.5)
|
859
|
-
|
860
|
-
#==============================================================================
|
861
|
-
def bsm_sigma(S0,X,Days,r0,sigmarange,Days1=0,div1=0,graph=True):
|
862
|
-
"""
|
863
|
-
功能:计算有红利支付的欧式期权BSM定价模型,看涨/看跌期权,波动率为变化范围
|
864
|
-
注意:
|
865
|
-
S0:标的物资产的当前价格
|
866
|
-
X:期权的行权价
|
867
|
-
sigmarange:标的物资产价格收益率的年化标准差范围
|
868
|
-
r0:年化无风险利率(需要转化为连续计算的无风险利率)
|
869
|
-
Days:距离到期日的天数
|
870
|
-
Days1:红利发放时距离到期日的天数,需要转换为年数
|
871
|
-
div1:红利金额
|
872
|
-
"""
|
873
|
-
#通用修改点
|
874
|
-
trange=sigmarange
|
875
|
-
#检查是否为列表
|
876
|
-
if not isinstance(trange,list):
|
877
|
-
print("#Error(bsm_sigma): target is not a range,",trange)
|
878
|
-
return
|
879
|
-
if len(trange) < 2:
|
880
|
-
print("#Error(bsm_sigma): not enough range for target,",trange)
|
881
|
-
return
|
882
|
-
|
883
|
-
#看涨期权
|
884
|
-
df1=bsm_call_sigma(S0,X,Days,r0,sigmarange,Days1=0,div1=0,graph=False)
|
885
|
-
df1.sort_index(ascending=True, inplace=True)
|
886
|
-
#看跌期权
|
887
|
-
df2=bsm_put_sigma(S0,X,Days,r0,sigmarange,Days1=0,div1=0,graph=False)
|
888
|
-
df2.sort_index(ascending=True, inplace=True)
|
889
|
-
|
890
|
-
#绘制双线图
|
891
|
-
titletxt='期权价格的变化趋势图'
|
892
|
-
colname1='Option Price'; label1='看涨期权'
|
893
|
-
colname2='Option Price'; label2='看跌期权'
|
894
|
-
ylabeltxt='期权价格'
|
895
|
-
|
896
|
-
fn1='波动率-->'
|
897
|
-
fn2='\n[期权信息]行权价='+str(X)+', 标的物市价='+str(S0)
|
898
|
-
fn3='\n年化无风险利率%='+str(round(r0*100.,2))+', 距离到期日天数='+str(Days)
|
899
|
-
if div1==0: fn4='\n本产品无红利收益'
|
900
|
-
else: fn4='\n发放红利时间距离到期天数='+str(Days1)+', 红利='+str(div1)
|
901
|
-
footnote=fn1+fn2+fn3+fn4
|
902
|
-
|
903
|
-
plot_2lines(df1,colname1,label1,df2,colname2,label2, \
|
904
|
-
ylabeltxt,titletxt,footnote)
|
905
|
-
|
906
|
-
return
|
907
|
-
|
908
|
-
if __name__=='__main__':
|
909
|
-
S0=42
|
910
|
-
X=40
|
911
|
-
Days=183
|
912
|
-
r0=0.015
|
913
|
-
sigmarange=[0.1,0.4]
|
914
|
-
Days1=90
|
915
|
-
div1=1.5
|
916
|
-
bsm_sigma(42,40,183,0.015,[0.1,0.4],90,1.5)
|
917
|
-
|
918
|
-
#==============================================================================
|
919
|
-
def iv_call_bsm(aop,S0,X,Days,r0,Days1=0,div1=0,precision=0.01,printout=True):
|
920
|
-
"""
|
921
|
-
功能:基于BSM模型,二分迭代法,计算隐含波动率,看涨期权
|
922
|
-
aop:实际期权价格
|
923
|
-
S0:标的物当前市价
|
924
|
-
X:标的物行权价
|
925
|
-
Days:距离到期日的天数
|
926
|
-
r0:年华无风险利率
|
927
|
-
Days1:预期红利收益发放日期距离到期日的天数,默认=0
|
928
|
-
div1:预期红利收益金额,默认=0
|
929
|
-
printout:是否显示计算结果,默认=True
|
930
|
-
"""
|
931
|
-
k=1
|
932
|
-
volLow=0.001 #设置波动率的最低值
|
933
|
-
volHigh=1.0 #设置波动率的最高值
|
934
|
-
|
935
|
-
#波动率最低值对应的期权价格
|
936
|
-
#cLow=bsCall(S,X,T,r,volLow)
|
937
|
-
cLow=bsm_call(S0,X,Days,r0,volLow,Days1,div1,printout=False)
|
938
|
-
|
939
|
-
#波动率最高值对应的期权价格
|
940
|
-
#cHigh=bsCall(S,X,T,r,volHigh)
|
941
|
-
cHigh=bsm_call(S0,X,Days,r0,volHigh,Days1,div1,printout=False)
|
942
|
-
|
943
|
-
#防止出现死循环
|
944
|
-
if cLow > aop or cHigh < aop:
|
945
|
-
print("#Error(iv_call_bsm): Option price not reasonable,",aop)
|
946
|
-
return None
|
947
|
-
#raise ValueError
|
948
|
-
|
949
|
-
while k ==1:
|
950
|
-
#cLow=bsCall(S,X,T,r,volLow)
|
951
|
-
cLow=bsm_call(S0,X,Days,r0,volLow,Days1,div1,printout=False)
|
952
|
-
#cHigh=bsCall(S,X,T,r,volHigh)
|
953
|
-
cHigh=bsm_call(S0,X,Days,r0,volHigh,Days1,div1,printout=False)
|
954
|
-
|
955
|
-
#取波动率的高低均值
|
956
|
-
volMid=(volLow+volHigh)/2.0
|
957
|
-
#cMid=bsCall(S,X,T,r,volMid)
|
958
|
-
cMid=bsm_call(S0,X,Days,r0,volMid,Days1,div1,printout=False)
|
959
|
-
|
960
|
-
#满足期权价格误差精度要求(0.01以下)则结束循环
|
961
|
-
if abs(cHigh-cLow) < precision: k=2
|
962
|
-
#否则,缩小范围,继续循环
|
963
|
-
elif cMid>aop: volHigh=volMid
|
964
|
-
else: volLow=volMid
|
965
|
-
|
966
|
-
iv=round(volMid,4)
|
967
|
-
if not printout: return iv
|
968
|
-
|
969
|
-
#显示
|
970
|
-
print("\n=== 隐含波动率: 二叉树迭代 ===")
|
971
|
-
print("看涨期权:")
|
972
|
-
print(" 期权现价 :",aop)
|
973
|
-
print(" 标的资产现价 :",S0)
|
974
|
-
print(" 标的资产行权价 :",X)
|
975
|
-
print(" 距离到期日的天数:",Days)
|
976
|
-
if not (div1 == 0):
|
977
|
-
print(" 预期红利 :",div1)
|
978
|
-
print(" 红利发放距离到期日的天数:",Days1)
|
979
|
-
print("隐含波动率:")
|
980
|
-
print(" 预计的年化波动率 :",iv)
|
981
|
-
print(" 对应的期权价格范围:",round(cLow,3),'-',round(cHigh,3))
|
982
|
-
print(" 迭代精度 :",precision)
|
983
|
-
return iv
|
984
|
-
|
985
|
-
#==============================================================================
|
986
|
-
def iv_put_bsm(aop,S0,X,Days,r0,Days1=0,div1=0,precision=0.01,printout=True):
|
987
|
-
"""
|
988
|
-
功能:基于BSM模型,二分迭代法,计算隐含波动率,看跌期权
|
989
|
-
aop:实际期权价格
|
990
|
-
S0:标的物当前市价
|
991
|
-
X:标的物行权价
|
992
|
-
Days:距离到期日的天数
|
993
|
-
r0:年华无风险利率
|
994
|
-
Days1:预期红利收益发放日期距离到期日的天数,默认=0
|
995
|
-
div1:预期红利收益金额,默认=0
|
996
|
-
printout:是否显示计算结果,默认=True
|
997
|
-
"""
|
998
|
-
k=1
|
999
|
-
volLow=0.001 #设置波动率的最低值
|
1000
|
-
volHigh=1.0 #设置波动率的最高值
|
1001
|
-
|
1002
|
-
#波动率最低值对应的期权价格
|
1003
|
-
#cLow=bsCall(S,X,T,r,volLow)
|
1004
|
-
cLow=bsm_put(S0,X,Days,r0,volLow,Days1,div1,printout=False)
|
1005
|
-
|
1006
|
-
#波动率最高值对应的期权价格
|
1007
|
-
#cHigh=bsCall(S,X,T,r,volHigh)
|
1008
|
-
cHigh=bsm_put(S0,X,Days,r0,volHigh,Days1,div1,printout=False)
|
1009
|
-
|
1010
|
-
#防止出现死循环
|
1011
|
-
if cLow > aop or cHigh < aop:
|
1012
|
-
print("#Error(iv_put_bsm): Option price not reasonable,",aop)
|
1013
|
-
return None
|
1014
|
-
#raise ValueError
|
1015
|
-
|
1016
|
-
while k ==1:
|
1017
|
-
#cLow=bsCall(S,X,T,r,volLow)
|
1018
|
-
cLow=bsm_put(S0,X,Days,r0,volLow,Days1,div1,printout=False)
|
1019
|
-
#cHigh=bsCall(S,X,T,r,volHigh)
|
1020
|
-
cHigh=bsm_put(S0,X,Days,r0,volHigh,Days1,div1,printout=False)
|
1021
|
-
|
1022
|
-
#取波动率的高低均值
|
1023
|
-
volMid=(volLow+volHigh)/2.0
|
1024
|
-
#cMid=bsCall(S,X,T,r,volMid)
|
1025
|
-
cMid=bsm_put(S0,X,Days,r0,volMid,Days1,div1,printout=False)
|
1026
|
-
|
1027
|
-
#满足期权价格误差精度要求(precision)则结束循环
|
1028
|
-
if abs(cHigh-cLow) < precision: k=2
|
1029
|
-
#否则,缩小范围,继续循环
|
1030
|
-
elif cMid>aop: volHigh=volMid
|
1031
|
-
else: volLow=volMid
|
1032
|
-
|
1033
|
-
iv=round(volMid,4)
|
1034
|
-
if not printout: return iv
|
1035
|
-
|
1036
|
-
#显示
|
1037
|
-
print("\n=== 隐含波动率: 二叉树迭代 ===")
|
1038
|
-
print("看跌期权:")
|
1039
|
-
print(" 期权现价 :",aop)
|
1040
|
-
print(" 标的资产现价 :",S0)
|
1041
|
-
print(" 标的资产行权价 :",X)
|
1042
|
-
print(" 距离到期日的天数:",Days)
|
1043
|
-
if not (div1 == 0):
|
1044
|
-
print(" 预期红利 :",div1)
|
1045
|
-
print(" 红利发放距离到期日的天数:",Days1)
|
1046
|
-
print("隐含波动率:")
|
1047
|
-
print(" 预计的年化波动率 :",iv)
|
1048
|
-
print(" 对应的期权价格范围:",round(cLow,3),'-',round(cHigh,3))
|
1049
|
-
print(" 迭代精度 :",precision)
|
1050
|
-
|
1051
|
-
return iv
|
1052
|
-
|
1053
|
-
#==============================================================================
|
1054
|
-
def binomial_american_call(S0,X,Days,r0,sigma,q0=0,steps=200,printout=True):
|
1055
|
-
"""
|
1056
|
-
功能:计算有红利支付的美式期权二叉树定价模型,看涨期权
|
1057
|
-
注意:
|
1058
|
-
S0:标的物资产的当前价格
|
1059
|
-
X为其行权价
|
1060
|
-
Days:距离到期日的天数,需要转换为距离到期日的年数=距离到期日的天数/365
|
1061
|
-
r0:年化无风险利率(需要转化为连续计算的无风险利率)
|
1062
|
-
sigma:标的物资产价格收益率的年化标准差
|
1063
|
-
q0:年化红利收益率,由于美式期权可能提前行权,故不考虑发放日期
|
1064
|
-
steps:二叉树的步骤
|
1065
|
-
"""
|
1066
|
-
from numpy import log,exp
|
1067
|
-
|
1068
|
-
#Days1为距离到期日的日历日天数
|
1069
|
-
t=Days/365.
|
1070
|
-
r=log(r0+1)
|
1071
|
-
q=log(q0+1)
|
1072
|
-
#调整标的物当前价
|
1073
|
-
S=S0
|
1074
|
-
|
1075
|
-
import numpy as np
|
1076
|
-
u=np.exp(sigma*np.sqrt(t/steps)); d=1/u
|
1077
|
-
|
1078
|
-
P=(np.exp((r-q)*t/steps)-d)/(u-d)
|
1079
|
-
prices=np.zeros(steps+1)
|
1080
|
-
c_values=np.zeros(steps+1)
|
1081
|
-
prices[0]=S*d**steps
|
1082
|
-
c_values[0]=np.maximum(prices[0]-X,0)
|
1083
|
-
|
1084
|
-
for i in range(1,steps+1):
|
1085
|
-
prices[i]=prices[i-1]*(u**2)
|
1086
|
-
c_values[i]=np.maximum(prices[i]-X,0)
|
1087
|
-
|
1088
|
-
for j in range(steps,0,-1):
|
1089
|
-
for i in range(0,j):
|
1090
|
-
prices[i]=prices[i+1]*d
|
1091
|
-
#c_values[i]=np.maximum((P*c_values[i+1]+(1-P)*c_values[i])/np.exp(r*t/steps),prices[i]-X)
|
1092
|
-
c_values[i]=np.maximum((P*c_values[i+1]+(1-P)*c_values[i])/np.exp((r-q)*t/steps),prices[i]-X)
|
1093
|
-
C=round(c_values[0],2)
|
1094
|
-
|
1095
|
-
if not printout: return C
|
1096
|
-
print("\n===== 二叉树期权定价 =====")
|
1097
|
-
print("适用情形: 美式期权,标的资产有红利")
|
1098
|
-
print("标的资产行权价 :",X)
|
1099
|
-
print("标的资产现价 :",S0)
|
1100
|
-
print("标的资产年化波动率 :",round(sigma,4))
|
1101
|
-
print("距离到期日的年数 :",round(t,2))
|
1102
|
-
print("连续计算的无风险收益率:",round(r,4)*100,'\b%')
|
1103
|
-
print("连续计算的红利率 :",round(q,4)*100,'\b%')
|
1104
|
-
print("二叉树迭代步数 :",steps)
|
1105
|
-
print("看涨期权的预期价格 :",round(C,4))
|
1106
|
-
|
1107
|
-
return C
|
1108
|
-
|
1109
|
-
#==============================================================================
|
1110
|
-
def binomial_american_put(S0,X,Days,r0,sigma,q0=0,steps=200,printout=True):
|
1111
|
-
"""
|
1112
|
-
功能:计算有红利支付的美式期权二叉树定价模型,看跌期权
|
1113
|
-
注意:
|
1114
|
-
S0:标的物资产的当前价格
|
1115
|
-
X为其行权价
|
1116
|
-
Days:距离到期日的天数,需要转换为距离到期日的年数=距离到期日的天数/365
|
1117
|
-
r0:年化无风险利率(需要转化为连续计算的无风险利率)
|
1118
|
-
sigma:标的物资产价格收益率的年化标准差
|
1119
|
-
q0:年化红利收益率,由于美式期权可能提前行权,故不考虑发放日期
|
1120
|
-
steps:二叉树的步骤
|
1121
|
-
"""
|
1122
|
-
from numpy import log,exp
|
1123
|
-
|
1124
|
-
#Days1为距离到期日的日历日天数
|
1125
|
-
t=Days/365.
|
1126
|
-
r=log(r0+1)
|
1127
|
-
q=log(q0+1)
|
1128
|
-
#调整标的物当前价
|
1129
|
-
S=S0
|
1130
|
-
|
1131
|
-
import numpy as np
|
1132
|
-
u=np.exp(sigma*np.sqrt(t/steps))
|
1133
|
-
d=1/u
|
1134
|
-
P=(np.exp((r-q)*t/steps)-d)/(u-d)
|
1135
|
-
prices=np.zeros(steps+1)
|
1136
|
-
c_values=np.zeros(steps+1)
|
1137
|
-
prices[0]=S*d**steps
|
1138
|
-
c_values[0]=np.maximum(X-prices[0],0)
|
1139
|
-
|
1140
|
-
for i in range(1,steps+1):
|
1141
|
-
prices[i]=prices[i-1]*(u**2)
|
1142
|
-
c_values[i]=np.maximum(X-prices[i],0)
|
1143
|
-
|
1144
|
-
for j in range(steps,0,-1):
|
1145
|
-
for i in range(0,j):
|
1146
|
-
prices[i]=prices[i+1]*d
|
1147
|
-
#c_values[i]=np.maximum((P*c_values[i+1]+(1-P)*c_values[i])/np.exp(r*t/steps),X-prices[i])#检查是否提前行权
|
1148
|
-
c_values[i]=np.maximum((P*c_values[i+1]+(1-P)*c_values[i])/np.exp((r-q)*t/steps),X-prices[i])#检查是否提前行权
|
1149
|
-
C=round(c_values[0],2)
|
1150
|
-
|
1151
|
-
if not printout: return C
|
1152
|
-
print("\n===== 二叉树期权定价 =====")
|
1153
|
-
print("适用情形: 美式期权,标的资产有红利")
|
1154
|
-
print("标的资产行权价 :",X)
|
1155
|
-
print("标的资产现价 :",S0)
|
1156
|
-
print("标的资产年化波动率 :",round(sigma,4))
|
1157
|
-
print("距离到期日的年数 :",round(t,2))
|
1158
|
-
print("连续计算的无风险收益率:",round(r,4)*100,'\b%')
|
1159
|
-
print("连续计算的红利率 :",round(q,4)*100,'\b%')
|
1160
|
-
print("二叉树迭代步数 :",steps)
|
1161
|
-
print("看跌期权的预期价格 :",round(C,4))
|
1162
|
-
|
1163
|
-
return C
|
1164
|
-
|
1165
|
-
#==============================================================================
|
1166
|
-
#==============================================================================
|
1167
|
-
#==============================================================================
|
1168
|
-
#==============================================================================
|
1169
|
-
if __name__=='__main__':
|
1170
|
-
ticker="AAPL"
|
1171
|
-
ticker="SPY"
|
1172
|
-
|
1173
|
-
def option_maturity(ticker,printout=True):
|
1174
|
-
"""
|
1175
|
-
功能:获得期权的各个到期日期
|
1176
|
-
注意:目前yfinance无法使用,股票期权链功能暂时不可用,可尝试yahooquery?
|
1177
|
-
"""
|
1178
|
-
"""
|
1179
|
-
if not test_yahoo_access():
|
1180
|
-
print(" #Warning(option_maturity): failed to access data source Yahoo Finance")
|
1181
|
-
return None
|
1182
|
-
"""
|
1183
|
-
import yfinance as yf
|
1184
|
-
# yf.__version__
|
1185
|
-
|
1186
|
-
opt = yf.Ticker(ticker)
|
1187
|
-
|
1188
|
-
#获得期权的各个到期日
|
1189
|
-
try:
|
1190
|
-
exp_dates=opt.options
|
1191
|
-
except:
|
1192
|
-
print(" #Error(option_maturity): failed to get option maturity dates for underlying",ticker)
|
1193
|
-
print(" Reasons: either",ticker,"does not exist or Yahoo Finance is currently inaccessible")
|
1194
|
-
return None
|
1195
|
-
|
1196
|
-
datelist=list(exp_dates)
|
1197
|
-
if not printout:
|
1198
|
-
return datelist
|
1199
|
-
|
1200
|
-
tname=get_stock_name1_en(ticker)
|
1201
|
-
|
1202
|
-
#显示结果
|
1203
|
-
print("\n===== 期权的时间序列 =====")
|
1204
|
-
print("标的资产:",tname)
|
1205
|
-
print("到期日期:")
|
1206
|
-
|
1207
|
-
num=len(datelist)
|
1208
|
-
for d in datelist:
|
1209
|
-
print(d,end=' ')
|
1210
|
-
pos=datelist.index(d)+1
|
1211
|
-
if (pos % 4 ==0) or (pos==num): print(' ')
|
1212
|
-
|
1213
|
-
print("总计:",num,"个日期")
|
1214
|
-
import datetime
|
1215
|
-
today = datetime.date.today()
|
1216
|
-
print("\n*** 数据来源: 雅虎财经,",today)
|
1217
|
-
|
1218
|
-
return datelist
|
1219
|
-
|
1220
|
-
if __name__=='__main__':
|
1221
|
-
ticker='AAPL'
|
1222
|
-
datelist=option_maturity(ticker)
|
1223
|
-
datelist=option_maturity('AAPL')
|
1224
|
-
datelist=option_maturity('000001.SS')
|
1225
|
-
|
1226
|
-
#================================================================
|
1227
|
-
if __name__=='__main__':
|
1228
|
-
ticker="AAPL"
|
1229
|
-
maturity_date="2025-2-21"
|
1230
|
-
|
1231
|
-
def option_chain(ticker,maturity_date='today',printout=True):
|
1232
|
-
"""
|
1233
|
-
功能:获得期权的各个到期日期,并列出某个到期日的期权合约
|
1234
|
-
"""
|
1235
|
-
mdate=maturity_date
|
1236
|
-
|
1237
|
-
if mdate=='today':
|
1238
|
-
import datetime as dt; stoday=dt.date.today()
|
1239
|
-
mdate=str(stoday)
|
1240
|
-
|
1241
|
-
import yfinance as yf
|
1242
|
-
opt = yf.Ticker(ticker)
|
1243
|
-
|
1244
|
-
#处理称为规范日期
|
1245
|
-
from datetime import datetime
|
1246
|
-
mdate2 = datetime.strptime(mdate, '%Y-%m-%d')
|
1247
|
-
mdate3 = datetime.strftime(mdate2,'%Y-%m-%d')
|
1248
|
-
|
1249
|
-
#获得一个到期日的所有期权合约
|
1250
|
-
try:
|
1251
|
-
optlist = opt.option_chain(mdate3)
|
1252
|
-
except:
|
1253
|
-
if printout:
|
1254
|
-
print(" #Error(option_chain): failed to get option chain for",ticker,'\b@',mdate)
|
1255
|
-
return None,None
|
1256
|
-
|
1257
|
-
opt_call=optlist.calls
|
1258
|
-
opt_call['underlyingAsset']=ticker
|
1259
|
-
opt_call['optionType']='Call'
|
1260
|
-
|
1261
|
-
inttodate=lambda x: int2date(x)
|
1262
|
-
opt_call['date']=opt_call['lastTradeDate'].apply(inttodate)
|
1263
|
-
opt_call['maturity']=mdate3
|
1264
|
-
|
1265
|
-
collist=['contractSymbol','underlyingAsset','optionType','date', \
|
1266
|
-
'maturity','strike','lastPrice','impliedVolatility','volume', \
|
1267
|
-
'inTheMoney','currency']
|
1268
|
-
opt_call2=opt_call[collist].copy()
|
1269
|
-
num_call=len(opt_call2)
|
1270
|
-
num_call_ITM=len(opt_call2[opt_call2['inTheMoney']==True])
|
1271
|
-
num_call_OTM=num_call-num_call_ITM
|
1272
|
-
|
1273
|
-
strike_min=min(opt_call2['strike'])
|
1274
|
-
strike_max=max(opt_call2['strike'])
|
1275
|
-
currency=opt_call2['currency'][0]
|
1276
|
-
|
1277
|
-
opt_put=optlist.puts
|
1278
|
-
opt_put['underlyingAsset']=ticker
|
1279
|
-
opt_put['optionType']='Put'
|
1280
|
-
opt_put['date']=opt_put['lastTradeDate'].apply(inttodate)
|
1281
|
-
opt_put['maturity']=mdate3
|
1282
|
-
opt_put2=opt_put[collist].copy()
|
1283
|
-
num_put=len(opt_put2)
|
1284
|
-
num_put_ITM=len(opt_put2[opt_put2['inTheMoney']==True])
|
1285
|
-
num_put_OTM=num_put-num_put_ITM
|
1286
|
-
|
1287
|
-
if not printout:
|
1288
|
-
return opt_call2, opt_put2
|
1289
|
-
|
1290
|
-
tname=get_stock_name1_en(ticker)
|
1291
|
-
|
1292
|
-
print("\n===== 期权链的结构 =====")
|
1293
|
-
print("标的资产:",tname)
|
1294
|
-
print("到期日期:",mdate)
|
1295
|
-
print("看涨期权:",num_call)
|
1296
|
-
print(" 实值/虚值:",num_call_ITM,'/',num_call_OTM)
|
1297
|
-
print("看跌期权:",num_put)
|
1298
|
-
print(" 实值/虚值:",num_put_ITM,'/',num_put_OTM)
|
1299
|
-
print("最低/最高行权价:",strike_min,'/',strike_max,currency)
|
1300
|
-
|
1301
|
-
import datetime
|
1302
|
-
stoday = datetime.date.today()
|
1303
|
-
print("\n*数据来源: 雅虎财经,",stoday)
|
1304
|
-
|
1305
|
-
#设置绘图数据
|
1306
|
-
df1=opt_call2.copy()
|
1307
|
-
df1.sort_values(by=['strike'],axis=0,ascending=[True],inplace=True)
|
1308
|
-
df1.set_index(['strike'],inplace=True)
|
1309
|
-
df1['exercise']=df1.index
|
1310
|
-
colname1='lastPrice'; label1='看涨期权价格'
|
1311
|
-
|
1312
|
-
df2=opt_put2.copy()
|
1313
|
-
df2.sort_values(by=['strike'],axis=0,ascending=[True],inplace=True)
|
1314
|
-
df2.set_index(['strike'],inplace=True)
|
1315
|
-
df2['exercise']=df2.index
|
1316
|
-
colname2='lastPrice'; label2='看跌期权价格'
|
1317
|
-
|
1318
|
-
ylabeltxt='期权价格('+currency+')'
|
1319
|
-
titletxt="期权价格与标的行权价格的关系"
|
1320
|
-
footnote="标的行权价("+currency+") -->\n"+ \
|
1321
|
-
"标的资产: "+tname+ \
|
1322
|
-
", "+"到期日: "+mdate+ \
|
1323
|
-
"\n数据来源: 雅虎财经, "+str(stoday)
|
1324
|
-
|
1325
|
-
#绘图
|
1326
|
-
import matplotlib.pyplot as plt
|
1327
|
-
plt.plot(df1.index,df1[colname1],color='red',linestyle='-',linewidth=1.5, \
|
1328
|
-
label=label1)
|
1329
|
-
|
1330
|
-
plt.plot(df2.index,df2[colname2],color='blue',linestyle='-',linewidth=1.5, \
|
1331
|
-
label=label2)
|
1332
|
-
|
1333
|
-
plt.ylabel(ylabeltxt,fontsize=ylabel_txt_size)
|
1334
|
-
plt.xlabel(footnote,fontsize=xlabel_txt_size)
|
1335
|
-
plt.title(titletxt,fontsize=title_txt_size)
|
1336
|
-
plt.legend(fontsize=legend_txt_size)
|
1337
|
-
plt.show()
|
1338
|
-
|
1339
|
-
|
1340
|
-
return opt_call2, opt_put2
|
1341
|
-
|
1342
|
-
if __name__=='__main__':
|
1343
|
-
ticker='AAPL'
|
1344
|
-
mdate='2022-6-17'
|
1345
|
-
dfc,dfp=option_chain(ticker,mdate)
|
1346
|
-
|
1347
|
-
#==============================================================================
|
1348
|
-
if __name__ =="__main__":
|
1349
|
-
ticker='AAPL'
|
1350
|
-
lastndays=7
|
1351
|
-
|
1352
|
-
#def predict_stock_trend_by_option(ticker,lastndays=7,power=4):
|
1353
|
-
def market_prospect_via_option(ticker,lastdays=7):
|
1354
|
-
"""
|
1355
|
-
功能:根据期权行权价及交易量预测标的物价格
|
1356
|
-
注意:本函数与price_prospect_via_option内容基本一致,图示方式略有不同
|
1357
|
-
"""
|
1358
|
-
lastndays=lastdays
|
1359
|
-
|
1360
|
-
DEBUG=False
|
1361
|
-
try:
|
1362
|
-
datelist=option_maturity(ticker,printout=False)
|
1363
|
-
except:
|
1364
|
-
print(" #Error(predict_stock_price_by_option): option info not found for",ticker)
|
1365
|
-
if datelist is None:
|
1366
|
-
print(" #Warning(predict_stock_price_by_option): options not found for",ticker)
|
1367
|
-
return None
|
1368
|
-
print("\nFound options with",len(datelist),"maturity dates for",ticker)
|
1369
|
-
|
1370
|
-
import pandas as pd
|
1371
|
-
df=pd.DataFrame(columns=['Ticker','Date','WA Strike','Total Options', \
|
1372
|
-
'Calls in Total%','OTM in Calls%','OTM Calls in Total%', \
|
1373
|
-
'Puts in Total%','OTM in Puts%','OTM Puts in Total%'])
|
1374
|
-
for d in datelist:
|
1375
|
-
print_progress_percent2(d,datelist,steps=5,leading_blanks=4)
|
1376
|
-
|
1377
|
-
if DEBUG: print("Processing options matured on",d)
|
1378
|
-
opt_call,opt_put=option_chain(ticker,d,printout=False)
|
1379
|
-
|
1380
|
-
numofcalls=len(opt_call)
|
1381
|
-
opt_call_otm=opt_call[opt_call['inTheMoney']==False]
|
1382
|
-
numofotmcalls=len(opt_call_otm)
|
1383
|
-
|
1384
|
-
numofputs=len(opt_put)
|
1385
|
-
opt_put_otm=opt_put[opt_put['inTheMoney']==False]
|
1386
|
-
numofotmputs=len(opt_put_otm)
|
1387
|
-
|
1388
|
-
totalopts=numofcalls+numofputs
|
1389
|
-
|
1390
|
-
callsintotal=round(numofcalls/totalopts*100,2)
|
1391
|
-
if numofcalls != 0:
|
1392
|
-
otmincalls=round(numofotmcalls/numofcalls*100,2)
|
1393
|
-
else:
|
1394
|
-
otmincalls=0
|
1395
|
-
otmcallsintotal=round(numofotmcalls/totalopts*100,2)
|
1396
|
-
|
1397
|
-
putsintotal=round(numofputs/totalopts*100,2)
|
1398
|
-
if numofputs != 0:
|
1399
|
-
otminputs=round(numofotmputs/numofputs*100,2)
|
1400
|
-
else:
|
1401
|
-
otminputs=0
|
1402
|
-
otmputsintotal=round(numofotmputs/totalopts*100,2)
|
1403
|
-
|
1404
|
-
opts=pd.concat([opt_call,opt_put])
|
1405
|
-
opts.sort_values('date',ascending=False,inplace=True)
|
1406
|
-
lasttradedate=list(opts['date'])[0]
|
1407
|
-
lastndate=date_adjust(lasttradedate, adjust=-lastndays)
|
1408
|
-
|
1409
|
-
#取最近几天的期权交易
|
1410
|
-
opts2=opts[opts['date']>=lastndate]
|
1411
|
-
opts2.dropna(inplace=True)
|
1412
|
-
wa_strike=round(((opts2['strike']*opts2['volume']).sum())/(opts2['volume'].sum()),2)
|
1413
|
-
|
1414
|
-
s=pd.Series({'Ticker':ticker,'Date':d,'WA Strike':wa_strike, \
|
1415
|
-
'Total Options':totalopts, \
|
1416
|
-
'Calls in Total%':callsintotal,'OTM in Calls%':otmincalls,'OTM Calls in Total%':otmcallsintotal, \
|
1417
|
-
'Puts in Total%':putsintotal,'OTM in Puts%':otminputs,'OTM Puts in Total%':otmputsintotal})
|
1418
|
-
try:
|
1419
|
-
df=df.append(s,ignore_index=True)
|
1420
|
-
except:
|
1421
|
-
df=df._append(s,ignore_index=True)
|
1422
|
-
|
1423
|
-
#建立日期索引
|
1424
|
-
todatetime=lambda x:pd.to_datetime(x)
|
1425
|
-
df['date']=df['Date'].apply(todatetime)
|
1426
|
-
df2=df.set_index(['date'])
|
1427
|
-
|
1428
|
-
#绘图1:Calls vs Puts比例
|
1429
|
-
import datetime
|
1430
|
-
today = datetime.date.today()
|
1431
|
-
|
1432
|
-
colname1='Calls in Total%'
|
1433
|
-
label1='Calls in Total%'
|
1434
|
-
colname2='Puts in Total%'
|
1435
|
-
label2='Puts in Total%'
|
1436
|
-
ylabeltxt='Percentage'
|
1437
|
-
titletxt="Option Comparison: "+ticker+", Calls vs Puts"
|
1438
|
-
|
1439
|
-
footnote="Source: Yahoo Finance, "+str(today)
|
1440
|
-
plot_line2(df2,ticker,colname1,label1, \
|
1441
|
-
df2,ticker,colname2,label2, \
|
1442
|
-
ylabeltxt,titletxt,footnote)
|
1443
|
-
|
1444
|
-
#绘图2:OTM Calls vs OTM Puts相对比例
|
1445
|
-
colname1='OTM in Calls%'
|
1446
|
-
label1='OTM in Calls%'
|
1447
|
-
colname2='OTM in Puts%'
|
1448
|
-
label2='OTM in Puts%'
|
1449
|
-
ylabeltxt='Percentage'
|
1450
|
-
titletxt="Option Relative Proportion Comparison\n("+ticker+", OTM Calls vs OTM Puts)"
|
1451
|
-
|
1452
|
-
footnote="Source: Yahoo Finance, "+str(today)
|
1453
|
-
plot_line2(df2,ticker,colname1,label1, \
|
1454
|
-
df2,ticker,colname2,label2, \
|
1455
|
-
ylabeltxt,titletxt,footnote)
|
1456
|
-
|
1457
|
-
#绘图3:OTM Calls vs OTM Puts绝对比例
|
1458
|
-
colname1='OTM Calls in Total%'
|
1459
|
-
label1='OTM Calls in Total%'
|
1460
|
-
colname2='OTM Puts in Total%'
|
1461
|
-
label2='OTM Puts in Total%'
|
1462
|
-
ylabeltxt='Percentage'
|
1463
|
-
titletxt="Option Absolute Proportion Comparison\n("+ticker+", OTM Calls vs OTM Puts)"
|
1464
|
-
|
1465
|
-
footnote="Source: Yahoo Finance, "+str(today)
|
1466
|
-
plot_line2(df2,ticker,colname1,label1, \
|
1467
|
-
df2,ticker,colname2,label2, \
|
1468
|
-
ylabeltxt,titletxt,footnote)
|
1469
|
-
|
1470
|
-
#绘图4:标的物价格预测
|
1471
|
-
df2x=df2.drop(df2[df2['Total Options']<=1].index)
|
1472
|
-
"""
|
1473
|
-
colname='WA Strike'
|
1474
|
-
collabel='Predicted Price'
|
1475
|
-
ylabeltxt=''
|
1476
|
-
titletxt="Predicting Prices via Options: "+ticker
|
1477
|
-
footnote="Source: Yahoo Finance, "+str(today)
|
1478
|
-
plot_line(df2x,colname,collabel,ylabeltxt,titletxt,footnote,power=power)
|
1479
|
-
"""
|
1480
|
-
|
1481
|
-
#打印预测结果
|
1482
|
-
compotm=lambda x:compare_otm(x)
|
1483
|
-
df2x['Trend']=df2x.apply(compotm,axis=1) #axis=1表示按行操作
|
1484
|
-
"""
|
1485
|
-
collist=['Date','Trend','WA Strike','Total Options','Calls in Total%','OTM in Calls%', \
|
1486
|
-
'Puts in Total%','OTM in Puts%']
|
1487
|
-
"""
|
1488
|
-
collist=['Date','Trend','Total Options','Calls in Total%','Puts in Total%', \
|
1489
|
-
'OTM in Calls%','OTM in Puts%','OTM Calls in Total%','OTM Puts in Total%']
|
1490
|
-
df3=df2x[collist]
|
1491
|
-
df3.rename(columns={'Total Options':'TotalOptions'}, inplace = True)
|
1492
|
-
df3.rename(columns={'Calls in Total%':'Calls%','Puts in Total%':'Puts%'}, inplace = True)
|
1493
|
-
df3.rename(columns={'OTM in Calls%':'OTMinCalls%','OTM in Puts%':'OTMinPuts%'}, inplace = True)
|
1494
|
-
df3.rename(columns={'OTM Calls in Total%':'OTM Calls/Total%','OTM Puts in Total%':'OTM Puts/Total%'}, inplace = True)
|
1495
|
-
|
1496
|
-
"""
|
1497
|
-
print("\n ======= Predicting Price Trend via Option Configuration: "+ticker+" =======")
|
1498
|
-
#设置打印对齐
|
1499
|
-
pd.set_option('display.max_columns', 1000)
|
1500
|
-
pd.set_option('display.width', 1000)
|
1501
|
-
pd.set_option('display.max_colwidth', 1000)
|
1502
|
-
pd.set_option('display.unicode.ambiguous_as_wide', True)
|
1503
|
-
pd.set_option('display.unicode.east_asian_width', True)
|
1504
|
-
print(df3.to_string(index=False))
|
1505
|
-
"""
|
1506
|
-
#lastdate,lastprice=get_last_close1(ticker)
|
1507
|
-
prices_tmp=security_trend(ticker,graph=False)
|
1508
|
-
lastdate=str(prices_tmp.tail(1).index.values[0].date())
|
1509
|
-
lastprice=str(prices_tmp.tail(1).Close.values[0])
|
1510
|
-
"""
|
1511
|
-
print(" Note:")
|
1512
|
-
print(" 1) Recent price:",lastprice,"\b,",lastdate,'\b.')
|
1513
|
-
print(" 2) +(-) predicts higher(lower) price than recent, ++(--) for more likely, +/- for undetermined trend.")
|
1514
|
-
print(" 3) Option trade period: recent "+str(lastndays)+" days. No stock splits in the period. Dates with only 1 option removed.")
|
1515
|
-
#print(" 4) Removed those samples with only one option, if any.")
|
1516
|
-
print(" "+footnote+'.')
|
1517
|
-
"""
|
1518
|
-
tname=get_stock_name1_en(ticker,short_name=True)
|
1519
|
-
titletxt="Predicting Price Trend via Option Configuration: "+tname
|
1520
|
-
footnote1="Note:\n"
|
1521
|
-
footnote2="1. Recent price: "+lastprice+", "+lastdate+'\n'
|
1522
|
-
footnote3="2. +(-) predicts higher(lower) price than recent, ++(--) more likely, +/- undetermined\n"
|
1523
|
-
footnote4="3. Period: recent "+str(lastndays)+" days. No stock splits in the period. Removed dates with 1 option only\n"
|
1524
|
-
footnote9=footnote1+footnote2+footnote3+footnote4+footnote
|
1525
|
-
|
1526
|
-
df_display_CSS(df3,titletxt=titletxt,footnote=footnote9,facecolor='papayawhip',decimals=2, \
|
1527
|
-
first_col_align='left',second_col_align='right', \
|
1528
|
-
last_col_align='right',other_col_align='right', \
|
1529
|
-
titile_font_size='15px',heading_font_size='13px', \
|
1530
|
-
data_font_size='13px')
|
1531
|
-
|
1532
|
-
return df2
|
1533
|
-
|
1534
|
-
|
1535
|
-
|
1536
|
-
|
1537
|
-
#================================================================
|
1538
|
-
if __name__=='__main__':
|
1539
|
-
intdate=1604350755
|
1540
|
-
|
1541
|
-
def int2date(intdate):
|
1542
|
-
"""
|
1543
|
-
功能:将数字转换为日期,10位数字为秒级,13位的为毫秒级
|
1544
|
-
输入:使用10位或13位整数表示的日期时间
|
1545
|
-
返回:yyyy-mm-dd hh:mm:ss
|
1546
|
-
"""
|
1547
|
-
import time
|
1548
|
-
intstr=str(intdate)
|
1549
|
-
|
1550
|
-
if len(intstr) == 10:
|
1551
|
-
tupTime = time.localtime(intdate) #秒时间戳
|
1552
|
-
#standardTime = time.strftime("%Y-%m-%d %H:%M:%S", tupTime)
|
1553
|
-
standardTime = time.strftime("%Y-%m-%d", tupTime)
|
1554
|
-
return standardTime
|
1555
|
-
|
1556
|
-
if len(intstr)==13:
|
1557
|
-
timeNum=intdate #毫秒时间戳
|
1558
|
-
timeTemp = float(timeNum/1000)
|
1559
|
-
tupTime = time.localtime(timeTemp)
|
1560
|
-
#standardTime = time.strftime("%Y-%m-%d %H:%M:%S", tupTime)
|
1561
|
-
standardTime = time.strftime("%Y-%m-%d", tupTime)
|
1562
|
-
return standardTime
|
1563
|
-
|
1564
|
-
#直接为日期时间结构
|
1565
|
-
standardTime = intdate.strftime("%Y-%m-%d")
|
1566
|
-
return standardTime
|
1567
|
-
|
1568
|
-
if __name__=='__main__':
|
1569
|
-
intdate1=1604349847
|
1570
|
-
int2date(intdate1)
|
1571
|
-
|
1572
|
-
intdate2=1566366547705
|
1573
|
-
int2date(intdate2)
|
1574
|
-
|
1575
|
-
import pandas as pd
|
1576
|
-
intdate3=pd.to_datetime('2020-11-03')
|
1577
|
-
int2date(intdate3)
|
1578
|
-
#==============================================================================
|
1579
|
-
#==============================================================================
|
1580
|
-
def compare_otm(row,spread=1.0):
|
1581
|
-
"""
|
1582
|
-
功能:比较OTM Call vs OTM Put的绝对比例大小,赋值+/-
|
1583
|
-
输入:df的一行
|
1584
|
-
输出:+/-
|
1585
|
-
"""
|
1586
|
-
if row['OTM Calls in Total%'] > row['OTM Puts in Total%']:
|
1587
|
-
result='+'
|
1588
|
-
if (row['Calls in Total%'] > row['Puts in Total%']) and ((row['OTM in Calls%'] > row['OTM in Puts%'])):
|
1589
|
-
result='++'
|
1590
|
-
|
1591
|
-
if row['OTM Calls in Total%'] < row['OTM Puts in Total%']:
|
1592
|
-
result='-'
|
1593
|
-
if (row['Calls in Total%'] < row['Puts in Total%']) and ((row['OTM in Calls%'] < row['OTM in Puts%'])):
|
1594
|
-
result='--'
|
1595
|
-
|
1596
|
-
if abs(row['OTM Calls in Total%'] - row['OTM Puts in Total%']) < spread:
|
1597
|
-
result='+/-'
|
1598
|
-
|
1599
|
-
return result
|
1600
|
-
|
1601
|
-
#==============================================================================
|
1602
|
-
def call_timevalue(row):
|
1603
|
-
"""
|
1604
|
-
功能:计算看涨期权的时间价值
|
1605
|
-
输入:df的一行
|
1606
|
-
输出:期权的时间价值
|
1607
|
-
"""
|
1608
|
-
#是否实值期权
|
1609
|
-
if row['inTheMoney']:
|
1610
|
-
tv=row['lastPrice']-row['lastSPrice']+row['strike']
|
1611
|
-
else:
|
1612
|
-
tv=row['lastPrice']
|
1613
|
-
return tv
|
1614
|
-
|
1615
|
-
def put_timevalue(row):
|
1616
|
-
"""
|
1617
|
-
功能:计算看跌期权的时间价值
|
1618
|
-
输入:df的一行
|
1619
|
-
输出:期权的时间价值
|
1620
|
-
"""
|
1621
|
-
#是否实值期权
|
1622
|
-
if row['inTheMoney']:
|
1623
|
-
tv=row['lastPrice']+row['lastSPrice']-row['strike']
|
1624
|
-
else:
|
1625
|
-
tv=row['lastPrice']
|
1626
|
-
return tv
|
1627
|
-
|
1628
|
-
#==============================================================================
|
1629
|
-
|
1630
|
-
if __name__ =="__main__":
|
1631
|
-
ticker='AAPL'
|
1632
|
-
lastndays=2
|
1633
|
-
|
1634
|
-
def price_prospect_via_option(ticker,lastdays=7,cutoff=[1.1,5.0,10.0]):
|
1635
|
-
"""
|
1636
|
-
功能:根据股票期权预测标的物价格
|
1637
|
-
算法:
|
1638
|
-
1、计算虚值看涨/看跌期权数量比例
|
1639
|
-
2、计算虚值看涨/看跌期权交易金额比例
|
1640
|
-
3、若虚值看涨期权占优,为看涨,并据此估计未来标的物价格;
|
1641
|
-
4、若虚值看跌期权占优,为看跌,并据此估计未来标的物价格;
|
1642
|
-
5、否则,为不明确
|
1643
|
-
返回:期权明细
|
1644
|
-
"""
|
1645
|
-
lastndays=lastdays
|
1646
|
-
|
1647
|
-
DEBUG=False
|
1648
|
-
print("Searching option chain for",ticker,'...',end='')
|
1649
|
-
|
1650
|
-
try:
|
1651
|
-
datelist=option_maturity(ticker,printout=False)
|
1652
|
-
except:
|
1653
|
-
print("\n #Warning(price_prospect_via_option): option info not found for",ticker)
|
1654
|
-
return None
|
1655
|
-
if datelist is None:
|
1656
|
-
print("\n #Warning(price_prospect_via_option): options not found for",ticker)
|
1657
|
-
return None
|
1658
|
-
print("found",len(datelist),"maturity dates of options")
|
1659
|
-
|
1660
|
-
#最新的标的物价格
|
1661
|
-
#print("Searching recent close price for",ticker,'...',end='')
|
1662
|
-
try:
|
1663
|
-
#lastsdate,lastsprice=get_last_close1(ticker)
|
1664
|
-
prices_tmp=security_trend(ticker,graph=False)
|
1665
|
-
lastsdate=str(prices_tmp.tail(1).index.values[0].date())
|
1666
|
-
lastsprice=str(prices_tmp.tail(1).Close.values[0])
|
1667
|
-
|
1668
|
-
except:
|
1669
|
-
print("\n #Error(price_prospect_via_option): failed in retrieving close price for",ticker)
|
1670
|
-
return None
|
1671
|
-
if (lastsdate is None) or (lastsprice is None):
|
1672
|
-
print("\n #Error(price_prospect_via_option): retrieving close price failed for",ticker)
|
1673
|
-
return None
|
1674
|
-
if DEBUG: print(lastsprice,'\b,',lastsdate)
|
1675
|
-
|
1676
|
-
import pandas as pd
|
1677
|
-
df=pd.DataFrame(columns=['Ticker','Date','Trend','Estimated Price', \
|
1678
|
-
'OTM Volume Call/Put','OTM Amount Call/Put','Spot Date','Spot Price'])
|
1679
|
-
for d in datelist:
|
1680
|
-
print_progress_percent2(d,datelist,steps=5,leading_blanks=4)
|
1681
|
-
|
1682
|
-
if DEBUG: print("Analyzing options matured on",d,'...')
|
1683
|
-
opt_call,opt_put=option_chain(ticker,d,printout=False)
|
1684
|
-
|
1685
|
-
if (opt_call is None) or (opt_put is None):
|
1686
|
-
if DEBUG:
|
1687
|
-
print(" #Warning(price_prospect_via_option): failed in retrieving options matured on",d)
|
1688
|
-
"""
|
1689
|
-
break
|
1690
|
-
return None
|
1691
|
-
"""
|
1692
|
-
continue
|
1693
|
-
|
1694
|
-
if (len(opt_call) == 0) or (len(opt_put) == 0):
|
1695
|
-
if DEBUG:
|
1696
|
-
print(" #Warning(price_prospect_via_option): retrieved zero options matured on",d)
|
1697
|
-
"""
|
1698
|
-
break
|
1699
|
-
return None
|
1700
|
-
"""
|
1701
|
-
continue
|
1702
|
-
|
1703
|
-
currency=list(opt_call['currency'])[0]
|
1704
|
-
|
1705
|
-
##########处理看涨期权##########
|
1706
|
-
if DEBUG: print(" Call volume: ",end='')
|
1707
|
-
opt_call['lastSDate']=lastsdate
|
1708
|
-
opt_call['lastSPrice']=lastsprice
|
1709
|
-
|
1710
|
-
#去掉无交易的期权
|
1711
|
-
opt_call.dropna(inplace=True)
|
1712
|
-
#只保留过去lastndays日历日的交易
|
1713
|
-
lasttdate=max(list(opt_call['date']))
|
1714
|
-
fromtdate=date_adjust(lasttdate, adjust=-lastndays)
|
1715
|
-
opt_call=opt_call[opt_call['date'] >= fromtdate]
|
1716
|
-
numofcalls=sum(opt_call['volume'])
|
1717
|
-
|
1718
|
-
"""
|
1719
|
-
#计算期权的时间价值:不一致,无法进一步利用
|
1720
|
-
calltv=lambda x:call_timevalue(x)
|
1721
|
-
opt_call['timeValue']=opt_call.apply(calltv,axis=1) #axis=1表示按行操作
|
1722
|
-
"""
|
1723
|
-
|
1724
|
-
#计算虚值期权的交易数量、交易金额和加权价格
|
1725
|
-
opt_call_otm=opt_call[opt_call['inTheMoney']==False]
|
1726
|
-
numofotmcalls=sum(opt_call_otm['volume'])
|
1727
|
-
amtofotmcalls=round(sum(opt_call_otm['lastPrice']*opt_call_otm['volume']),2)
|
1728
|
-
avopofotmcalls=round((amtofotmcalls/numofotmcalls),2)
|
1729
|
-
if DEBUG: print("total",int(numofcalls),'\b, OTM',int(numofotmcalls),end='')
|
1730
|
-
|
1731
|
-
#基于加权价格判断行权价
|
1732
|
-
opt_call_otm.sort_values('lastPrice',ascending=True,inplace=True)
|
1733
|
-
strikelist=list(opt_call_otm['strike'])
|
1734
|
-
lastPricelist=list(opt_call_otm['lastPrice'])+[avopofotmcalls]
|
1735
|
-
lastPricelist=sorted(lastPricelist,reverse=False)
|
1736
|
-
avoppos=lastPricelist.index(avopofotmcalls)
|
1737
|
-
if avoppos > 0:
|
1738
|
-
op1=lastPricelist[avoppos-1]
|
1739
|
-
strike1=strikelist[avoppos-1]
|
1740
|
-
op2=lastPricelist[avoppos+1]
|
1741
|
-
strike2=strikelist[avoppos]
|
1742
|
-
avspofotmcalls=round(min(strike1,strike2)+abs(strike1-strike2)*((avopofotmcalls-min(op1,op2))/abs(op1-op2)),2)
|
1743
|
-
else:
|
1744
|
-
avspofotmcalls=strikelist[avoppos]
|
1745
|
-
if DEBUG: print(", done!")
|
1746
|
-
|
1747
|
-
##########处理看跌期权##########
|
1748
|
-
if DEBUG: print(" Put volume: ",end='')
|
1749
|
-
opt_put['lastSDate']=lastsdate
|
1750
|
-
opt_put['lastSPrice']=lastsprice
|
1751
|
-
|
1752
|
-
#去掉无交易的期权
|
1753
|
-
opt_put.dropna(inplace=True)
|
1754
|
-
#只保留过去lastndays日历日的交易
|
1755
|
-
lasttdate=max(list(opt_put['date']))
|
1756
|
-
fromtdate=date_adjust(lasttdate, adjust=-lastndays)
|
1757
|
-
opt_put=opt_put[opt_put['date'] >= fromtdate]
|
1758
|
-
numofputs=sum(opt_put['volume'])
|
1759
|
-
|
1760
|
-
"""
|
1761
|
-
#计算期权的时间价值:不一致,无法进一步利用
|
1762
|
-
puttv=lambda x:put_timevalue(x)
|
1763
|
-
opt_put['timeValue']=opt_put.apply(puttv,axis=1) #axis=1表示按行操作
|
1764
|
-
"""
|
1765
|
-
|
1766
|
-
#计算虚值期权的交易数量、交易金额和加权价格
|
1767
|
-
opt_put_otm=opt_put[opt_put['inTheMoney']==False]
|
1768
|
-
numofotmputs=sum(opt_put_otm['volume'])
|
1769
|
-
amtofotmputs=round(sum(opt_put_otm['lastPrice']*opt_put_otm['volume']),2)
|
1770
|
-
avopofotmputs=round((amtofotmputs/numofotmputs),2)
|
1771
|
-
if DEBUG: print("total",int(numofputs),'\b, OTM',int(numofotmputs),end='')
|
1772
|
-
|
1773
|
-
#基于加权价格判断行权价
|
1774
|
-
opt_put_otm.sort_values('lastPrice',ascending=True,inplace=True)
|
1775
|
-
strikelist=list(opt_put_otm['strike'])
|
1776
|
-
lastPricelist=list(opt_put_otm['lastPrice'])+[avopofotmputs]
|
1777
|
-
lastPricelist=sorted(lastPricelist,reverse=False)
|
1778
|
-
avoppos=lastPricelist.index(avopofotmputs)
|
1779
|
-
if avoppos > 0:
|
1780
|
-
op1=lastPricelist[avoppos-1]
|
1781
|
-
strike1=strikelist[avoppos-1]
|
1782
|
-
op2=lastPricelist[avoppos+1]
|
1783
|
-
strike2=strikelist[avoppos]
|
1784
|
-
avspofotmputs=round(min(strike1,strike2)+abs(strike1-strike2)*((avopofotmputs-min(op1,op2))/abs(op1-op2)),2)
|
1785
|
-
else:
|
1786
|
-
avspofotmputs=strikelist[avoppos]
|
1787
|
-
if DEBUG: print(", done!")
|
1788
|
-
|
1789
|
-
#比较虚值看涨/看跌期权的数量和交易金额
|
1790
|
-
if DEBUG: print(" Evaluating price trend ...",end='')
|
1791
|
-
rateqty=round(numofotmcalls/numofotmputs,2)
|
1792
|
-
rateamt=round(amtofotmcalls/amtofotmputs,2)
|
1793
|
-
trend='+/-'
|
1794
|
-
star1=cutoff[0]; star2=cutoff[1]; star3=cutoff[2]
|
1795
|
-
#加强判断:以rateamt为主,结合rateqty
|
1796
|
-
if (rateqty > 1.0) and (rateamt > star1):
|
1797
|
-
trend='+'
|
1798
|
-
if (rateqty < 1.0) and (rateamt < 1.0/star1):
|
1799
|
-
trend='-'
|
1800
|
-
if (rateqty > star2) and (rateamt > star2):
|
1801
|
-
trend='++'
|
1802
|
-
if (1/rateqty > star2) and (1/rateamt > star2):
|
1803
|
-
trend='--'
|
1804
|
-
if (rateqty > star3) and (rateamt > star3):
|
1805
|
-
trend='+++'
|
1806
|
-
if (1/rateqty > star3) and (1/rateamt > star3):
|
1807
|
-
trend='---'
|
1808
|
-
|
1809
|
-
estsprice=lastsprice
|
1810
|
-
if (trend[0] == '+') and (trend != '+/-'):
|
1811
|
-
estsprice=avspofotmcalls
|
1812
|
-
if trend[0]=='-':
|
1813
|
-
estsprice=avspofotmputs
|
1814
|
-
if trend == '+/-':
|
1815
|
-
estsprice=(avspofotmcalls + avspofotmputs)/2.0
|
1816
|
-
|
1817
|
-
s=pd.Series({'Ticker':ticker,'Date':d,'Trend':trend,'Estimated Price':estsprice, \
|
1818
|
-
'OTM Volume Call/Put':rateqty,'OTM Amount Call/Put':rateamt,'Spot Date':lastsdate,'Spot Price':lastsprice})
|
1819
|
-
try:
|
1820
|
-
df=df.append(s,ignore_index=True)
|
1821
|
-
except:
|
1822
|
-
df=df._append(s,ignore_index=True)
|
1823
|
-
if DEBUG: print(", done!")
|
1824
|
-
|
1825
|
-
#建立日期索引
|
1826
|
-
todatetime=lambda x:pd.to_datetime(x)
|
1827
|
-
df['date']=df['Date'].apply(todatetime)
|
1828
|
-
df2=df.set_index(['date'])
|
1829
|
-
|
1830
|
-
tname=get_stock_name1_en(ticker,short_name=True)
|
1831
|
-
|
1832
|
-
#绘图1:虚值Calls vs Puts数量比例
|
1833
|
-
import datetime
|
1834
|
-
stoday = datetime.date.today()
|
1835
|
-
|
1836
|
-
df2['Benchmark']=1.0
|
1837
|
-
colname1='OTM Volume Call/Put'
|
1838
|
-
label1='虚值看涨/看跌期权合约数量比例'
|
1839
|
-
colname2='Benchmark'
|
1840
|
-
label2='等比例线'
|
1841
|
-
ylabeltxt='比例'
|
1842
|
-
titletxt="期权链中的合约数量: "+tname+", 虚值看涨/看跌期权比例"
|
1843
|
-
|
1844
|
-
footnote="数据来源:雅虎财经, "+str(stoday)
|
1845
|
-
plot_line2(df2,ticker,colname1,label1, \
|
1846
|
-
df2,ticker,colname2,label2, \
|
1847
|
-
ylabeltxt,titletxt,footnote)
|
1848
|
-
|
1849
|
-
#绘图2:OTM Calls vs OTM Puts交易金额比例
|
1850
|
-
colname1='OTM Amount Call/Put'
|
1851
|
-
label1='虚值看涨/看跌期权交易金额比例'
|
1852
|
-
titletxt="期权链中的交易金额: "+tname+", 虚值看涨/看跌期权比例"
|
1853
|
-
|
1854
|
-
plot_line2(df2,ticker,colname1,label1, \
|
1855
|
-
df2,ticker,colname2,label2, \
|
1856
|
-
ylabeltxt,titletxt,footnote)
|
1857
|
-
|
1858
|
-
#绘图3:预测的标的物价格
|
1859
|
-
df2['Benchmark']=lastsprice
|
1860
|
-
colname1='Estimated Price'
|
1861
|
-
label1='预期价格'
|
1862
|
-
colname2='Benchmark'
|
1863
|
-
label2='当前价格'
|
1864
|
-
ylabeltxt='价格('+currency+')'
|
1865
|
-
titletxt="期权链与标的价格预期: "+tname
|
1866
|
-
|
1867
|
-
plot_line2(df2,ticker,colname1,label1, \
|
1868
|
-
df2,ticker,colname2,label2, \
|
1869
|
-
ylabeltxt,titletxt,footnote)
|
1870
|
-
|
1871
|
-
#打印预测结果
|
1872
|
-
collist=['Date','Trend','Estimated Price','OTM Volume Call/Put','OTM Amount Call/Put']
|
1873
|
-
df3=df2[collist]
|
1874
|
-
"""
|
1875
|
-
print("\n ======= 基于期权链结构的股票走势和价格预期: "+tname+" =======")
|
1876
|
-
#设置打印对齐
|
1877
|
-
pd.set_option('display.max_columns', 1000)
|
1878
|
-
pd.set_option('display.width', 1000)
|
1879
|
-
pd.set_option('display.max_colwidth', 1000)
|
1880
|
-
pd.set_option('display.unicode.ambiguous_as_wide', True)
|
1881
|
-
pd.set_option('display.unicode.east_asian_width', True)
|
1882
|
-
df3.columns=['日期','标的物价格走势','标的物价格预期','虚值看涨/看跌合约数量比例','虚值看涨/看跌交易金额比例']
|
1883
|
-
print(df3.to_string(index=False))
|
1884
|
-
|
1885
|
-
print(" 注:")
|
1886
|
-
print(" 1) 当前价格: "+currency+str(lastsprice),"\b,",lastsdate,'\b.')
|
1887
|
-
print(" 2) +(-)表示价格将比当前变高(低), +/-表示趋势不明朗.")
|
1888
|
-
print(" 3) 期权交易样本期间: 最近"+str(lastndays)+"个日历日,且期间内未发生分拆.")
|
1889
|
-
print(" 4) 价格估计可能随时变化,越远期的估计可能准确度越欠佳.")
|
1890
|
-
print(" "+footnote+'.')
|
1891
|
-
"""
|
1892
|
-
titletxt="期权链与标的价格预期: "+tname
|
1893
|
-
footnote1="注:\n"
|
1894
|
-
footnote2="1、当前价格: "+currency+str(lastsprice)+", "+lastsdate+'\n'
|
1895
|
-
footnote3="2、+(-)表示价格将比当前变高(低), +/-表示趋势不明朗\n"
|
1896
|
-
footnote4="3、期权交易样本期间: 最近"+str(lastndays)+"个日历日,且期间内未发生分拆\n"
|
1897
|
-
footnote5="4) 价格价格估计可能随时变化,越远期的估计可能准确度越欠佳\n"
|
1898
|
-
|
1899
|
-
footnote9=footnote1+footnote2+footnote3+footnote4+footnote5+footnote
|
1900
|
-
|
1901
|
-
df_display_CSS(df3,titletxt=titletxt,footnote=footnote9,facecolor='papayawhip',decimals=2, \
|
1902
|
-
first_col_align='left',second_col_align='right', \
|
1903
|
-
last_col_align='right',other_col_align='right', \
|
1904
|
-
titile_font_size='15px',heading_font_size='13px', \
|
1905
|
-
data_font_size='13px')
|
1906
|
-
|
1907
|
-
return df2
|
1908
|
-
|
1909
|
-
if __name__ =="__main__":
|
1910
|
-
df=stock_trend_by_option('AAPL',7)
|
1911
|
-
|
1912
|
-
#==============================================================================
|
1913
|
-
#==============================================================================
|
1914
|
-
#==============================================================================
|
1915
|
-
#==============================================================================
|
1916
|
-
|
1917
|
-
#==============================================================================
|
1918
|
-
|
1919
|
-
|
1920
|
-
|
1921
|
-
|
1922
|
-
|
1923
|
-
|
1924
|
-
|
1925
|
-
|