| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- # 克隆自聚宽文章:https://www.joinquant.com/post/14348
- # 标题:场外期权对冲策略回测框架-(以Whally-Wilmott为例)
- # 作者:颖硕
- import datetime
- import time
- from scipy.stats import norm
- import jqdata
- import numpy
- def initialize(context):
- set_options(context)
- set_params()
-
- # 设置期权参数
- def set_options(context):
- g.securities='002724.XSHE'
- g.K=1
- g.T=30
- g.rf=0.09
- g.sigma=secstd(context)
- g.S0=secinitialprice(context)
- g.startdate=context.run_params.start_date
- g.maturity=maturity(context)
- g.NP=context.portfolio.cash/1.05
- g.YearDay=float(365)
- g.secname=get_security_info(g.securities).display_name
- log.info('##################################基本信息####################################')
- log.info('标的代码->',g.securities,'标的名称->',g.secname,'名义本金->',g.NP)
- log.info('起始日期->',g.startdate,'到期日期->',g.maturity)
- log.info('期初价格->',g.S0,'执行价格->',g.K,'合约期限->',g.T,\
- '无风险利率->',g.rf,'波动率->',round(g.sigma,2))
- log.info('##############################################################################')
- # 设置参数
- def set_params():
- set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, \
- close_commission=0.0003, min_commission=5), type='stock')
- set_option('use_real_price', True)
- set_benchmark(g.securities)
- set_slippage(FixedSlippage(0))
- def before_trading_start(context):
- # 获取当日日期
- current_date=context.current_dt.date()
- # 第一天建仓
- if current_date==g.startdate:
- delta=DeltaCalculator(context,g.S0)
- DeltaPosition=round(g.NP/g.S0*delta/100)*100
- g.lastdelta=delta
- order_target(g.securities,DeltaPosition)
- # 第二天到倒数第二天判断分红拆股
- if current_date>g.startdate and current_date<g.maturity:
- checkadj=get_price(g.securities,end_date=current_date,\
- fields=['close','factor'],fq='pre',count=2)
- if checkadj.iloc[0,1]!=checkadj.iloc[1,1]:
- temp=g.S0
- g.S0=round(g.S0*checkadj.iloc[0,1]/checkadj.iloc[1,1],2)
- log.info('期初价格调整',temp,'-->',g.S0)
- # 到期日清仓
- if current_date==g.maturity:
- order_target(g.securities,0)
- log.info('今天清仓日->',str(current_date))
- # 到期日之后就没事了
- if current_date>g.maturity:
- pass
-
- def handle_data(context, data):
- # 获取时间并判断
- current_time=context.current_dt
- current_date=current_time.date()
- # 只有第二天到倒数第二天才会有对冲
- # 9点30会取到昨天的收盘价,所以我们跳过这一分钟。
- if current_date>g.startdate and current_date<g.maturity and \
- (current_time.hour>9 or current_time.minute>30):
- # 中间交易日的触发对冲条件
- price=history(1,'1m', field='close',security_list=g.securities,\
- fq=None)
- currentdelta=DeltaCalculator(context,price.iloc[0,0])
- threshold=WhalleyWilmottThrehold(context,price.iloc[0,0])
-
- if abs(g.lastdelta-currentdelta)>threshold:
- delta=DeltaCalculator(context,price.iloc[0,0])
- DeltaPosition=round(g.NP/g.S0*delta/100)*100
- g.lastdelta=delta
- order_target(g.securities,DeltaPosition)
- def secstd(context):
- end_date=context.current_dt.date()
- start_date=end_date-datetime.timedelta(days=365)
- price=get_price(g.securities,start_date=start_date,end_date=end_date,frequency='daily',fields='close',skip_paused=False,fq='pre')
- rets=np.diff(np.log(price),axis=0)
- std=rets.std()*sqrt(250)
- return std
- def secinitialprice(context):
- start_date=context.current_dt.date()
- S0=get_price(g.securities,start_date=start_date,end_date=start_date,frequency='daily',fields='open',fq=None)
- return S0.values[0][0]
- def maturity(context):
- matday=g.startdate+datetime.timedelta(days=g.T)
- array=jqdata.get_all_trade_days()
- index=numpy.where(array>=matday)[0][0] #datetime.date(matday.year,matday.month,matday.day)
- truematday=array[index]
- return truematday
- def DeltaCalculator(context,S):
- current_date=context.current_dt.date()
- Tau=(g.maturity-current_date).days+1
- d1=(np.log(S/(g.S0*g.K))+(g.rf+g.sigma**2/2)*(Tau/g.YearDay))\
- /(g.sigma*np.sqrt(Tau/g.YearDay))
- delta=norm.cdf(d1)
- return delta
-
- def GammaCalculator(context,S):
- current_date=context.current_dt.date()
- Tau=(g.maturity-current_date).days+1
- d1=(np.log(S/(g.S0*g.K))+(g.rf+g.sigma**2/2)*(Tau/g.YearDay))\
- /(g.sigma*np.sqrt(Tau/g.YearDay))
- gamma=norm.pdf(d1)/(S*g.sigma*np.sqrt(Tau/g.YearDay))
- return gamma
- def WhalleyWilmottThrehold(context,S):
- current_date=context.current_dt.date()
- risktolerance=5
- tradingcost=0.00055
- Tau=(g.maturity-current_date).days+1
- gamma=GammaCalculator(context,S)
- a=exp(-g.rf*Tau/g.YearDay)*tradingcost*S*gamma**2
- wwt=(3.0/2.0*a/risktolerance)**(1.0/3.0)
- return wwt
-
|