forked from qmhedging/poboquant
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathIH与50ETF对冲-改进历史波动率计算 IH-50ETF Opt hedge HV cal fix
262 lines (198 loc) · 11.4 KB
/
IH与50ETF对冲-改进历史波动率计算 IH-50ETF Opt hedge HV cal fix
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# coding:utf-8
#!/usr/bin/env python
from PoboAPI import *
import datetime
import numpy as np
#用poboquant python实现,在poboquant上运行,如果有问题 可加群 726895887 咨询
#上证50指数期货 和 50ETF期权的对冲交易,当ETF隐含波动率较高时就买IH期货并做空ETF看涨期权
#Hedge IH Index Futures with 50ETF call options, open positions when IV's high
#开始时间,用于初始化一些参数
def OnStart(context) :
print "system starting..."
#设定一个全局变量品种
g.code0 = "510050.SHSE"
#g.code1 = "10001315.SHSE" # 50ETF购12月2600
#g.code2="IH1812.CFFEX"
#订阅实时数据,用于驱动OnQuote事件
SubscribeQuote(g.code0) #批量订阅行情
#订阅K线数据,用于驱动OnBar事件
#SubscribeBar(g.code1, BarType.Day)
#登录交易账号,需在主页用户管理中设置账号,并把证券测试替换成您的账户名称
context.myaccOPT = None
if context.accounts.has_key("回测期权") :
print "登录交易账号[回测期权]"
if context.accounts["回测期权"].Login() :
context.myaccOPT = context.accounts["回测期权"]
context.myaccFUT = None
if context.accounts.has_key("回测期货") :
print "登录交易账号[回测期货]"
if context.accounts["回测期货"].Login() :
context.myaccFUT = context.accounts["回测期货"]
def GetMonthRotation2(CurrentDay,contractleg1,contractleg2):
#print "in function"+str(CurrentDay) # month rolling for financialstock index futures
yearstring=int(CurrentDay.year)
monthstring=int(CurrentDay.month)
daystring=int(CurrentDay.day)
if daystring<15: #股指为合约到期月份第三个周五
if monthstring<10:
return [contractleg1+str((str(yearstring))[2:4])+str("0")+str(monthstring),contractleg2+str((str(yearstring))[2:4])+str("0")+str(monthstring)]
if monthstring>=10:
return [contractleg1+str((str(yearstring))[2:4])+str(monthstring),contractleg2+str((str(yearstring))[2:4])+str(monthstring)]
if daystring>=15:
if monthstring<9:
return [contractleg1+str((str(yearstring))[2:4])+str("0")+str(monthstring+1),contractleg2+str((str(yearstring))[2:4])+str("0")+str(monthstring+1)]
if monthstring>=9 and monthstring<11:
return [contractleg1+str((str(yearstring))[2:4])+str(monthstring+1),contractleg2+str((str(yearstring))[2:4])+str(monthstring+1)]
if monthstring==11:
return [contractleg1+str((str(yearstring))[2:4])+str("12"),contractleg1+str((str(yearstring))[2:4])+str("12")]
if monthstring==12:
return [contractleg1+str((str(yearstring+1))[2:4])+str("01"),contractleg1+str((str(yearstring+1))[2:4])+str("01")]
# if monthstring>=1 and monthstring<3 :
# # ma 9 05 vs ma 9 09
# return [contractleg1+str((str(yearstring))[2:4])+str("03"),contractleg2+str((str(yearstring))[2:4])+str("03")]
# if monthstring>=3 and monthstring<6:
# # ma 9 09 ma 0 01
# return [contractleg1+str((str(yearstring))[2:4])+str("06"),contractleg2+str((str(yearstring))[2:4])+str("06")]
# if monthstring>=6 and monthstring<9:
# return [contractleg1+str((str(yearstring))[2:4])+str("09"),contractleg2+str((str(yearstring))[2:4])+str("09")]
# if monthstring>=9 and monthstring<=12:
# return [contractleg1+str((str(yearstring+1))[2:4])+str("03"),contractleg1+str((str(yearstring))[2:4])+str("03")]
def Getop(code):#获取期权合约,包括call和put合约
dyndata = GetQuote(code)
now1 = dyndata.now
now50 = round(now1,1) + 0.05
cutime = GetCurrentTime()
if cutime.day >15 and cutime.month<12:
tim = cutime.month + 1
month_time = datetime.datetime(month=tim, year=cutime.year,day = 20)
elif cutime.day >15 and cutime.month==12:
tim = 1
yea = cutime.year + 1
month_time = datetime.datetime(month=tim, year=yea,day = 20)
else:
month_time = cutime
atmopc = GetAtmOptionContract(code,month_time,now50,0)
atmopp = GetAtmOptionContract(code,month_time,now50,1)
return atmopc,atmopp
def GetDaystoExpire(op):#计算期权到期日
info1 = GetContractInfo(op)
kill = info1['行权到期日']
cutime = GetCurrentTime()
c = cutime.date()
n = (kill - c).days
print n
#实时行情事件,当有新行情出现时调用该事件
def OnQuote(context, code) :
g.code0="510050.SHSE"
tradingdate=GetCurrentTime().date()#获取当前日期
FutContract = "IH"
contract1=FutContract
contract2=FutContract
g.code1 = str(GetMonthRotation2(tradingdate,contract1,contract2)[0])+str(".CFFEX")#获取IH股指期货合约
print "g.code1",g.code1
opc,opp = Getop(g.code0)#获取期权合约代码
#获取最新行情
dyndata1 = GetQuote(g.code1).now#.now指最新价,详细属性见API文档
dyndata0 = GetQuote(g.code0).now
dyndata2 = GetQuote(opc).now
tradingtime=GetQuote(g.code0).time#获取50ETF交易时间,用于计算波动率
print "tradingtime ",tradingtime
if dyndata1 and dyndata0 and dyndata2 :
now1 = dyndata1
now0 = dyndata0
now2 = dyndata2
#打印最新价
log.info("50ETF买权最新价: " + str(dyndata2))
log.info("510050最新价: " + str(dyndata0))
log.info("IH股指期货最新价:" + str(dyndata1))
#klinedata0 = GetHisData(g.code0, BarType.Day)#获取K线数据
CalOBJ = CreateCalcObj() #创建一个计算对象
option = PBObj()
#option.StartDate = datetime.datetime(int(tradingtime.year), int(tradingtime.month), int(tradingtime.day))
yearstring=int(tradingtime.year)
#print "yearstring=int(tradingtime.year)",int(tradingtime.year)
monthstring=int(tradingtime.month)
daystring=int(tradingtime.day)
#准备计算50ETF的历史波动率
option.EndDate=datetime.datetime(yearstring,monthstring,daystring)
option.Count = 30 #计算50ETF 30天历史波动率
klinedata0 = GetHisDataByField(g.code0, BarType.Day,"close",option)
#print "len(klinedata) ",len(klinedata)
if len(klinedata0)>0:
Kl = np.array(klinedata0, dtype=np.double)
HisVola=CalOBJ.GetVolatility(Kl)
print HisVola
OptDirection=0 # 0 for call, 1 for put
AssetType=0 # 0 for stock opt,1 for etf opt, 2 for futures opt
AssetPrice=now0 # here is the 510050 price
print "AssetPrice ",AssetPrice
StrikePrice=round(now0,1) + 0.05 # for 50ETF购12月2600 strike price
InterestRate=4.35*0.01 # the risk free interest rate
print "g.code ",g.code0
#dates=GetOptionsLastDates("m1901.DCE")# not working
#dates=GetOptionsLastDates("SR901C6000.CZCE") # not working
#dates=GetOptionsLastDates("510050.SHSE")# working
#dates=GetOptionsLastDates("m1805-C-3300.DCE")
OptInfo = GetContractInfo(opc)#查询期权信息
ExpDates=OptInfo['行权到期日']
print "dates of expire ",str(ExpDates)
#ExpireinYear=(GetOptionsLastDates(g.code1) - tradingtime).days / 365.0 # years to expire
ExpireinYear=(ExpDates - tradingdate).days / 365.0 # years to expire
print "ExpireinYear ",ExpireinYear
OptionPrice=now2 # for option price
#calculate the implied volatility
#format (direction,asset type,asset price,strikeprice,HisVola,interest rate,expire year,option price)
print "opt para:"+str(OptDirection)+","+str(AssetType)+","+str(AssetPrice)+","+str(StrikePrice)+","+str(HisVola)+","+str(InterestRate)+","+str(ExpireinYear)+","+str(OptionPrice)
ImpliedVola=CalOBJ.GetImpliedVolatility(OptDirection,AssetType,AssetPrice,StrikePrice,HisVola,InterestRate,ExpireinYear,OptionPrice)
print "Implied Volatility is " + str(ImpliedVola)
balOPT = context.myaccOPT.AccountBalance #获取账户资金状况
posmarginOPT=balOPT.MarketValue
balFUT = context.myaccFUT.AccountBalance #获取账户资金状况
posmarginFUT=balFUT.MarketValue
posmargin=posmarginOPT + posmarginFUT
pos = context.myaccOPT.GetPositions()
poslength=len(pos)
print "持仓合约数: "+str(poslength)
#如果配置好交易账号了,可以根据条件下单,需把下面中的证券测试账号换成您设置的账号名称
#if len(klinedata1) > 1 and ImpliedVola>0.23 and context.myaccOPT and context.myaccFUT and posmargin<600000 :
if ImpliedVola>0.20 and posmargin<600000 :
#
print "open positions with IV at "+str(ImpliedVola)
print "trading day "+str(tradingtime)
print "期权持仓市值 "+str(posmargin)
context.myaccOPT.InsertOrder(opc, BSType.SellOpen, dyndata2, 30)#sell options
context.myaccFUT.InsertOrder(g.code1, BSType.BuyOpen, dyndata1, 1)#buy IH futures
if ImpliedVola<0.14 and poslength>0 :
#
print "Close positions,take profit with IV"+str(ImpliedVola)
print "trading day "+str(tradingtime)
context.myaccOPT.InsertOrder(opc, BSType.BuyClose, dyndata2, 30)
context.myaccFUT.InsertOrder(g.code1, BSType.SellClose, dyndata1, 1)
if ImpliedVola>0.25 and poslength>0 :
#
print "sell close the spread,cut loss with IV "+str(ImpliedVola)
print "trading day "+str(tradingtime)
context.myaccOPT.InsertOrder(opc, BSType.BuyClose, dyndata2, 30)
context.myaccFUT.InsertOrder(g.code1, BSType.SellClose, dyndata1, 1)
if poslength>0:
FutPos = context.myaccFUT.GetPositions()
if len(FutPos)>0:
for i in FutPos:
if i.contract<>g.code1:#处理头寸换月 rolling positions
FutClosePrice=GetQuote(i.contract)
FutCloseVolume=i.availvolume
print "平仓快到期期货头寸"
context.myaccOPT.InsertOrder(opc, BSType.BuyClose, dyndata2, 30*FutCloseVolume)
context.myaccFUT.InsertOrder(i.contract, BSType.SellClose, FutClosePrice, FutCloseVolume)
for t in pos:
if GetDaystoExpire(t.contract)<=3:
OptClosePrice=GetQuote(t.contract)
OptCloseVolume=t.availvolume
print "平仓快到期期权头寸"
context.myaccOPT.InsertOrder(i.contract, BSType.BuyClose, OptClosePrice, OptCloseVolume)
context.myaccFUT.InsertOrder(g.code1, BSType.SellClose, dyndata1, round(OptCloseVolume/30))
#委托回报事件,当有委托回报时调用
def OnOrderChange(context, AccountName, order) :
#打印委托信息,id是编号,volume是数量,详细见API文档
print "委托编号: " + order.id + " 账号名称: " + AccountName
print "Vol: " + str(order.volume) + " Price: " + str(order.price)