# 克隆自聚宽文章: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.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_date9 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