运用期货合约对冲风险时,要尽量选择能够抵消风险的期货合约,风险可能与商品价格、利率、汇率、股票价格或其他变量的波动有关,完美套期保值(Perfect hedge)在理论上存在,能够完全抵消风险。
该例以空头套期保值为例,运用股指期货演示了套期保值的过程。空头套期保值(short hedge)是指套期保值者选择期货的空头头寸进行风险对冲。
C公司在2020年6月11日购买了市值为1.2医院的沪深300指数ETF基金,购买时沪深300指数恰好为4000点,为了能够对冲指数在短期内下跌的风险,基金经理在当天运用沪深300股指期货IF2006合约的空头进行套期保值,期货的价格恰好是4000点,合约到期日是当年的6月19日。由于合约乘数每点300元,需要持有100手空头头寸。暂不考虑交易费用和保证金,当指数下跌1个点时,期货将获得3万元的盈利;当指数上涨1个点时,期货将面临3万元的亏损。
第1步:导入NumPy模块和Matplotlib模块,NumPy是Python一种开源的数值计算扩展模块,可以用来储存和处理大型矩阵,Marplotlib是Python的可视化模块。
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['']
plt.rcParams['axes.unicode_minus']=False
第2步:创建沪深300指数数组,该数组是取值在[3500,4500]去见的等差数列,即利用linspace,输入三个参数(起始值,终止值,数值间元素的个数),并且计算沪深300指数ETF基金现货收益、期货合约收益以及整个投资组合(包括现货和期货)的收益。1.2e8代表1.2×108,计算现货收益的公式为(指数价格-初始价格)×基金市值÷初始价格,计算期货合约的收益的公式为-(指数价格-初始价格)×空头数量×合约乘数,整个投资组合的收益为期货与现货收益之和。
fund=1.2e8 #购买基金时的基金市值
index=4000 #购买基金时沪深300指数的点位
N=100 #持有沪深300股指期货合约空头数量
M=300 #沪深300股指期货合约乘数
index_list=np.linspace(3500,4500,200) #创建沪深300指数不同点位的数组
profit_spot=(index_list-index)*fund/index #现货投资的收益
profit_future=-(index_list-index)*N*M #期货合约的收益
profit_portfolio=profit_spot+profit_future #整个投资组合的收益
第3步:将现货投资收益、期货合约收益以及套期保值后的整个投资组合收益进行可视化。figure函数用于定义画面大小,plot为曲线图的绘制,第一个第二个参数分别表示输入x轴和y轴的数据,label表示曲线的标签,lw=2.5表示曲线的宽是2.5磅。xlabel为x轴的坐标标签,xticks为x轴的刻度。legend为显示图例,title为图例的标题,通过fontsize=数字控制标题字体的大小。grid为控制网格,通常不用输入参数。show的作用为显示图形。
plt.figure(figsize=(9,6))
plt.plot(index_list,profit_spot,label=u'沪深300指数ETF基金',lw=2.5)
plt.plot(index_list,profit_future,label=u'沪深300指数期货合约',lw=2.5)
plt.plot(index_list,profit_portfolio,label=u'套期保值的投资组合',lw=2.5)
plt.xlabel(u'沪深300指数点位',fontsize=13)
plt.xticks(fontsize=13)
plt.ylabel(u'盈亏',fontsize=13)
plt.yticks(fontsize=13)
plt.title(u'空头套期保值的盈亏情况')
plt.legend(fontsize=13)
plt.grid()
plt.show()
得出的结论为,完美的空头套保期货合约的空头头寸收益,恰好抵补了现货投资的亏损,通过套期保值后的投资组合盈亏为0。
1. 注意程序中的大小写问题
2. 注意首行的缩进问题
3. 注意括号特别是小括号、中括号、大括号等的运用,注意括号的套用
4. 注意引号的中英文形式
2020年6月19日,E基金公司认为沪深300指数已经达到了阶段性顶部,未来股指会大概率回调,因此运用沪深300股指期货IF2007合约100手空头头寸进行套期保值,并且成交时的期货价格恰好为4000点,该期货合约到期日为2020年7月17日。F期货公司提供的沪深300股指期货的保证金比率是15%,因此对E基金公司而言,只需投入4000×100×300×15%=1800万元就可以开展1.2亿元期货合约的交易。E基金公司采用的是期货空头头寸,因此如果期货价格上涨1%,E基金公司将亏损120万元;如果期货价格下跌1%,则E基金公司将盈利120万元。因此期货价格变动±1%,E基金公司的收益率是±6.67%。
中国的保证金制度为当前合约价格的固定百分比,如本例中F期货公司提供的沪深300股指期货的保证金比率是15%,因此对E基金公司而言,只需投入4000×100×300×15%=1800万元就可以开展1.2亿元期货合约的交易。国外保证金制度为提前设定的固定值,在提交初始保证金后,如果保证金余额跌至维持保证金以下,则需交齐保证金至初始保证金额度,否则将强行平仓或交割。
E基金公司的期货空头头寸需要按照达成交易的当天及随后交易日的每日结算价进行结算,这种结算方式成为每日无负债结算或逐日盯市。
该案例通过Python快速计算E基金公司从2020年6月19日至7月17日每个交易日期货合约收益、累积收益以及保证金余额,并且不考虑保证金的追加。
第1步:导入pandas模块,pandas天然包含了金融时间序列的要素,是面板数据(panel data)与数据分析(data analysis)的结合。
import pandas as pd
第2步:导入数据,输入相关的期货合约参数并给变量赋值。注意文件路径的输入,sheetname表示需要从Excel中导入的工作表名称,header指定了列名行,header=0即取工作表第一行作为指定列名行,index_col指定了某一列作为索引列,index_co=0表示将第一列作为索引列。
price_IF2007=pd.read_excel('/Users/r.y./Desktop/金融工程学python/配套数据/数据/第10章/沪深300股指期货2007合约结算价(2020年6月19日至7月17日).xlsx',sheet_name="Sheet1",header=0,index_col=0) #导入外部数据
margin0=1.8e7 #初始保证金
N_short=100 #合约空头数量
P0=4000 #成交价格
M=300 #合约乘数
第3步:计算并构造2020年6月19日至7月17日每个交易日累计盈亏、当日盈亏和保证金余额3个时间序列并修改列名。计算期货每个交易日的累计盈亏公式为累积浮动盈亏=(卖出成交价-当日结算价)×卖出量=(当日结算价-买入成交价)×买入量,当日浮动盈亏=(当日结算价-上一交易日结算价)×持仓量。修改列名需要rename函数,并输入参数column=({‘原名称’:’新名称’})。iloc函数通过输入行号的方式来输入对应的数据,行号0代表第1行。
profit_sum_IF2007=-N_short*M*(price_IF2007-P0) #计算期货合约累计盈亏
profit_sum_IF2007=profit_sum_IF2007.rename(columns={'IF2007合约结算价':'合约累积盈亏'}) #变更列名
profit_daily_IF2007=profit_sum_IF2007-profit_sum_IF2007.shift(1) #计算期货合约每日的盈亏
profit_daily_IF2007.iloc[0]=profit_sum_IF2007.iloc[0] #首个交易日当日盈亏等于当天累计盈亏
profit_daily_IF2007=profit_daily_IF2007.rename(columns={'合约累积盈亏':'合约当日盈亏'}) #变更列名
margin_daily_IF2007=profit_sum_IF2007+margin0 #计算每日期货合约保证金余额(不考虑追加保证金)
margin_daily_IF2007=margin_daily_IF2007.rename(columns={'合约累积盈亏':'保证金余额'}) #变更列名
第4步:将数据框进行拼接,并输出最终的计算结果,concat([数据框1,数据框2,数据框3,...],axis=0或1),axis=0为按行拼接,axis=1为按列拼接。
data_IF2007=pd.concat([profit_daily_IF2007,profit_sum_IF2007,margin_daily_IF2007],axis=1) #将3个数据框按列拼接
data_IF2007 #查看结果
应用的数据
1. 注意程序中的大小写问题
2. 注意文件位置读取时将文件所在位置写明的问题
3. 注意首行的缩进问题
4. 注意括号特别是小括号、中括号、大括号等的运用,注意括号的套用
5. 注意引号的中英文形式
在实践中,经常会出现期货合约的基础资产与被套期保值的资产是两种并不一致的资产,即为交叉套期保值(cross hedging)。用来衡量交叉套期保值的效果的变量即为套期保值比率(hedging ratio),简称“套保比率”,是指持有期货合约的头寸数量预备对冲资产风险敞口数量的比率。当期货合约的基础资产与被套期保值的资产完全相同时,套保比率就等于1.0。但是采用交叉套期保值时套保比率设为1.0并非最优的选择,套保比率的选择应当使得套期保值后,包括期货合约在内的整个投资组合价值变化的方差达到最小,这就引出了最优套保比率的概念。最优套保比率也称最小方差套保比率取决于被套期保值资产价格变化与期货价格变化之间的关系。
ΔS表示在套期保值期间内,被套期保值资产价格S的变化
ΔF表示在套期保值期间内,用于套期保值的期货价格F的变化
该公式将期货价格的变化作为自变量,将被套期保值资产价格的变化作为因变量,从而用期货价格的变化线性表达被套期保值资产价格的变化。
α是截距项,ε是残差项,h*是ΔS对ΔF进行线性回归时所产生的最优拟合直线的斜率,h*是最优套保比率。该处应用线性回归模型并用最小二乘法进行了拟合,从而简便地求出线性回归模型的参数,并使拟合数据与实际数据之间的误差的平方和最小。线性回归方程的判定系数(也称可决系数)R2就是套期保值效率(hedge effectiveness),R2的取值处于[0,1]区间中,R2值越高说明套期保值效率越高。
根据线性回归模型中的斜率计算公式,可以得到最优套保比率h*的表达式:
σS是被套期保值资产价格变化ΔS的标准差,σF是期货价格变化ΔF的标准差,ρ是ΔS与ΔF之间的相关系数。该公式表明最优套保比率等于被套期保值资产价格变化与期货价格变化的相关系数乘两个价格变化标准差之间的比率。
股指期货合约中,根据资本资产定价模型,最优套保比率h*等于被套期保值投资组合的贝塔值。
G公司持有上证180指数ETF基金,该公司希望通过股指期货合约对该基金进行套期保值,假定可选的套期保值期货合约分别是上证50股指期货IH2009合约、沪深300股指期货IF2009合约以及中证500股指期货IC2009合约,3个期货合约的上市首日均是2020年1月20日,最后交易日均是2020年9月18日。G公司需要从这3个期货合约中选择最合适的套期保值期货合约,并计算相应的最优套保比率。
第1步:导入NumPy、Pandas、Matplotlib模块。pandas天然包含了金融时间序列的要素,是面板数据(panel data)与数据分析(data analysis)的结合。NumPy是Python一种开源的数值计算扩展模块,可以用来储存和处理大型矩阵,Marplotlib是Python的可视化模块。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['']
plt.rcParams['axes.unicode_minus']=False
from pandas.plotting import register_matplotlib_converters
register_matplotlib_converters()
第2步:从外部导入2020年1月20日至9月18日期间每个交易日的上证180指数ETF基金净值以及3只股指期货合约的收盘价数据,并计算相应的日收益率。注意文件路径的输入,sheetname表示需要从Excel中导入的工作表名称,header指定了列名行,header=0即取工作表第一行作为指定列名行,index_col指定了某一列作为索引列,index_col=0表示将第一列作为索引列。注意编写程序时应根据文件展示的列名分别输入期货合约的名称,不能照葫芦画瓢。
fund_future=pd.read_excel('/Users/r.y./Desktop/金融工程学python/配套数据/数据/第10章/上证180指数基金净值和三只A股股指期货合约收盘价数据.xlsx',sheet_name="Sheet1",header=0,index_col=0) #导入外部数据
fund_future.columns #查看数据框的列名
R_fund=np.log(fund_future['上证180指数基金']/fund_future['上证180指数基金'].shift(1)) #计算基金的日收益率
R_fund=R_fund.dropna() #删除缺失值
R_IH2009=np.log(fund_future['IH2009合约']/fund_future['IH2009合约'].shift(1)) #计算上证50股指期货IH2009合约的日收益率
R_IH2009=R_IH2009.dropna() #删除缺失值
R_IF2009=np.log(fund_future['IF2009合约']/fund_future['IF2009合约'].shift(1)) #计算沪深300股指期货IF2009合约的日收益率
R_IF2009=R_IF2009.dropna() #删除缺失值
R_IC2009=np.log(fund_future['IC2009合约']/fund_future['IC2009合约'].shift(1)) #计算中证500股指期货IC2009合约的日收益率
R_IC2009=R_IC2009.dropna() #删除缺失值
第3步 建立以基金的日收益率作为被解释变量、以上证50股指期货IH2009合约的日收益率作为被解释变量的线性回归模型。运用的是StatsModel中的api子模块。
import statsmodels.api as sm #导入statsmodels的子模块api
R_IH2009_addcons=sm.add_constant(R_IH2009) #生成增加常数项的时间序列
model_fund_IH2009=sm.OLS(R_fund,R_IH2009_addcons).fit() #构建基金日收益率与上证50股指期货IH2009合约日收益率的线性回归模型
model_fund_IH2009.summary() #输出线性回归模型的结果
第4步 建立以基金的的日收益率作为被解释变量、以沪深300股指期货IF2009合约的日收益率作为被解释变量的线性回归模型。
R_IF2009_addcons=sm.add_constant(R_IF2009) #生成增加常数项的时间序列
model_fund_IF2009=sm.OLS(R_fund,R_IF2009_addcons).fit() #构建基金日收益率与沪深300股指期货IF2009合约日收益率的线性回归模型
model_fund_IF2009.summary() #输出线性回归模型的结果
第5步 建立以基金的的日收益率作为被解释变量、以中证500股指期货IC2009合约的日收益率作为被解释变量的线性回归模型。
R_IC2009_addcons=sm.add_constant(R_IC2009)
model_fund_IC2009=sm.OLS(R_fund,R_IC2009_addcons).fit()
model_fund_IC2009.summary()
综合以上3个线性回归模型的结果,以沪深300股指期货IF2009合约的日收益率作为解释变量的线性回归模型的判定系数R2最高,达到了0.928,因此将选择沪深300股指期货IF2009合约作为套期保值的期货合约。
第6步 将最终拟合的最优套保比率通过可视化的方式进行展示
model_fund_IF2009.params #输出线性回归的常数项和贝塔值
cons=model_fund_IF2009.params[0] #线性回归的常数项
beta=model_fund_IF2009.params[1] #线性回归的贝塔值
plt.figure(figsize=(9,6))
plt.scatter(R_IF2009,R_fund,marker='o') #绘制散点图
plt.plot(R_IF2009,cons+beta*R_IF2009,'r-',lw=2.5) #绘制拟合的直线
plt.xlabel(u'沪深300指数期货IF2009合约',fontsize=13)
plt.xticks(fontsize=13)
plt.ylabel(u'上证180指数ETF基金',fontsize=13)
plt.yticks(fontsize=13)
plt.title(u'沪深300指数期货IF2009合约与上证180指数ETF基金的日收益率散点图',fontsize=13)
plt.grid('True')
plt.show()
通过分析可得运用沪深300股指期货IF2009合约作为套期保值工具,最优套保比率为线性回归中的贝塔值0.828601
应用的数据:
投资者还需要关心的是运用多少数量的期货合约进行套期保值,即为套期保值的最优合约数量。令QA表示被套期保值资产的数量(或金额);QF表示1份期货合约的规模(或金额);N*表示用于套期保值的最优合约数量。
在完美套期保值的情形下,存在如下的恒等式:
该式意味着用于套期保值的期货合约盈利(亏损)正好与被套期保值资产亏损完全抵消。同时将最优套保比率公式带入,经过调整,得到套期保值的最优合约数量的表达式:
第一步:定义一个计算套期保值的最优合约数量的函数。在自定义函数N_future中,只需要输入最优套保比率、被套期保值资产的数量或金额以及1份期货合约的规模或金额,就可以迅速计算得到套期保值的最优合约数量。
def N_future(h,Q_A,Q_F):
'''定义一个计算套期保值的最优合约数量的函数
h:代表最优套保比率
Q_A:代表被套期保值资产的数量(或金额)
Q_F:代表1份期货合约的规模(或金额)'''
N=h*Q_A/Q_F #计算套期保值的最优合约数量
return N
在该例中,H基金公司在2020年10月12日按照净值4.058买入上证180指数ETF基金共计5000万份,与此同时,基金公司希望运用沪深300股指期货IF2011合约空头头寸进行套期保值,该合约上市日为2020年9月21日,到期日为2020年11月20日,当天(2020年10月12日)期货合约结算价4775.6点用于计算套期保值的合约数量。假设期货最优套保比率等于0.828601。
300代表着期货合约乘数是每点300元。四舍五入得到H基金公司应该运用的最优合约数量是117手空头头寸。
第2步:运用自定义函数N_future,直接计算套期保值最优数量。
share_fund=5e7 #购买上证180指数ETF基金的份数
price_fund=4.058 #2020年10月12日基金收盘净值
value_fund=share_fund*price_fund #基金的市值
price_IF2011=4775.6 #2020年11月12日期货合约结算价
M=300 #期货合约乘数
value_IF2011=price_IF2011*M #期货合约价值
h_IF2011=model_fund_IF2009.params[1] #IF2011合约的最优套保比率
N_IF2011=N_future(h=h_IF2011,Q_A=value_fund,Q_F=value_IF2011) #计算期货合约数量
print('用于套期保值的沪深300股指期货IF2011合约数量(张)',round(N_IF2011,0))
追加保证金风险
一、课程引入
结合上一次课讲到的关于套期保值的例题,都是在暂不考虑期货保证金的前提下展开分析。然而,期货合约便是采用保证金方式进行交易,这与前面介绍的债券、股票以及互换合约在交易方式上存在极大的差异,因此即使是针对套期保值的期货交易在某种程度上也会比债券、股票以及互换合约具有更高的风险。
二、知识点补充,回顾保证金
要参与期货交易,买卖双方都必须在期货公司开立专门的保证金账户,并存入一定数量的保证金,这个保证金也称为初始保证金(initial margin)。
而当保证金账户的余额低于交易所规定的维持保证金(maintenance margin)水平时,期货公司就会通知交易者在期限内把保证金水平补足到一定的标准,否则就会被强制平仓。而这一要求补充保证金的行为就称为保证金追加通知(margin call)。交易者必须存入的额外的金额被称为变动保证金(variation margin)。我国期货市场都未设置维持保证金,也就是说,只要客户保证金水平低于要求的水平就会接到保证金追加通知,如果客户不及时追加,就有可能被强制平仓。
三、代码讲解
1、外部数据导入
data_AU2008=pd.read_excel('文件位置',sheet_name="Sheet1",header=0,index_col=0)
sheet_name=‘Sheet1':得到的是名为'Sheet1'的数据
header :指定标题行
index_col: 指定列索引
2、数据框的性质——index与columns函数
index函数查看行索引名
columns函数查看列名
3、修改列名
运用rename函数,并且输入重要的参数columns={‘原名称’:’新名称’}
如下举例:
(上图为例4-4的日交易数据)
四、案例分析
第一步:导入数据库
第二步:从外部导入沪深300股指期货IF2007合约在2020年6月19日至7月17日期间的结算价数据,并且输入相关期货合约参数。
第三步:分别计算并构造出2020年6月19日至7月17日每个交易日期合约累计盈亏、当日盈亏以及保证金余额这3个时间序列(数据框格式)
合约日收益= -合约张数*合约乘数*(当天结算价-上一日结算价),其中将6月19日合约的收益作为初始交易价格
保证金余额=初始保证金(1800万元)+当天的合约累计收益
第四步:输出结果
输出的结果与表10-10完全一致,同时从表中不难发现,如果不追加保证金,则E基金公司的保证金账户的余额在7月6日至7月15日期间为负值,保证金的风险控制功能也就形同虚设了。因此,为了保证保证金的余额不为负值,期货公司会设置维持保证金。