BS_WhalleyWilmott.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. # 克隆自聚宽文章:https://www.joinquant.com/post/14348
  2. # 标题:场外期权对冲策略回测框架-(以Whally-Wilmott为例)
  3. # 作者:颖硕
  4. import datetime
  5. import time
  6. from scipy.stats import norm
  7. import jqdata
  8. import numpy
  9. def initialize(context):
  10. set_options(context)
  11. set_params()
  12. # 设置期权参数
  13. def set_options(context):
  14. g.securities='002724.XSHE'
  15. g.K=1
  16. g.T=30
  17. g.rf=0.09
  18. g.sigma=secstd(context)
  19. g.S0=secinitialprice(context)
  20. g.startdate=context.run_params.start_date
  21. g.maturity=maturity(context)
  22. g.NP=context.portfolio.cash/1.05
  23. g.YearDay=float(365)
  24. g.secname=get_security_info(g.securities).display_name
  25. log.info('##################################基本信息####################################')
  26. log.info('标的代码->',g.securities,'标的名称->',g.secname,'名义本金->',g.NP)
  27. log.info('起始日期->',g.startdate,'到期日期->',g.maturity)
  28. log.info('期初价格->',g.S0,'执行价格->',g.K,'合约期限->',g.T,\
  29. '无风险利率->',g.rf,'波动率->',round(g.sigma,2))
  30. log.info('##############################################################################')
  31. # 设置参数
  32. def set_params():
  33. set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, \
  34. close_commission=0.0003, min_commission=5), type='stock')
  35. set_option('use_real_price', True)
  36. set_benchmark(g.securities)
  37. set_slippage(FixedSlippage(0))
  38. def before_trading_start(context):
  39. # 获取当日日期
  40. current_date=context.current_dt.date()
  41. # 第一天建仓
  42. if current_date==g.startdate:
  43. delta=DeltaCalculator(context,g.S0)
  44. DeltaPosition=round(g.NP/g.S0*delta/100)*100
  45. g.lastdelta=delta
  46. order_target(g.securities,DeltaPosition)
  47. # 第二天到倒数第二天判断分红拆股
  48. if current_date>g.startdate and current_date<g.maturity:
  49. checkadj=get_price(g.securities,end_date=current_date,\
  50. fields=['close','factor'],fq='pre',count=2)
  51. if checkadj.iloc[0,1]!=checkadj.iloc[1,1]:
  52. temp=g.S0
  53. g.S0=round(g.S0*checkadj.iloc[0,1]/checkadj.iloc[1,1],2)
  54. log.info('期初价格调整',temp,'-->',g.S0)
  55. # 到期日清仓
  56. if current_date==g.maturity:
  57. order_target(g.securities,0)
  58. log.info('今天清仓日->',str(current_date))
  59. # 到期日之后就没事了
  60. if current_date>g.maturity:
  61. pass
  62. def handle_data(context, data):
  63. # 获取时间并判断
  64. current_time=context.current_dt
  65. current_date=current_time.date()
  66. # 只有第二天到倒数第二天才会有对冲
  67. # 9点30会取到昨天的收盘价,所以我们跳过这一分钟。
  68. if current_date>g.startdate and current_date<g.maturity and \
  69. (current_time.hour>9 or current_time.minute>30):
  70. # 中间交易日的触发对冲条件
  71. price=history(1,'1m', field='close',security_list=g.securities,\
  72. fq=None)
  73. currentdelta=DeltaCalculator(context,price.iloc[0,0])
  74. threshold=WhalleyWilmottThrehold(context,price.iloc[0,0])
  75. if abs(g.lastdelta-currentdelta)>threshold:
  76. delta=DeltaCalculator(context,price.iloc[0,0])
  77. DeltaPosition=round(g.NP/g.S0*delta/100)*100
  78. g.lastdelta=delta
  79. order_target(g.securities,DeltaPosition)
  80. def secstd(context):
  81. end_date=context.current_dt.date()
  82. start_date=end_date-datetime.timedelta(days=365)
  83. price=get_price(g.securities,start_date=start_date,end_date=end_date,frequency='daily',fields='close',skip_paused=False,fq='pre')
  84. rets=np.diff(np.log(price),axis=0)
  85. std=rets.std()*sqrt(250)
  86. return std
  87. def secinitialprice(context):
  88. start_date=context.current_dt.date()
  89. S0=get_price(g.securities,start_date=start_date,end_date=start_date,frequency='daily',fields='open',fq=None)
  90. return S0.values[0][0]
  91. def maturity(context):
  92. matday=g.startdate+datetime.timedelta(days=g.T)
  93. array=jqdata.get_all_trade_days()
  94. index=numpy.where(array>=matday)[0][0] #datetime.date(matday.year,matday.month,matday.day)
  95. truematday=array[index]
  96. return truematday
  97. def DeltaCalculator(context,S):
  98. current_date=context.current_dt.date()
  99. Tau=(g.maturity-current_date).days+1
  100. d1=(np.log(S/(g.S0*g.K))+(g.rf+g.sigma**2/2)*(Tau/g.YearDay))\
  101. /(g.sigma*np.sqrt(Tau/g.YearDay))
  102. delta=norm.cdf(d1)
  103. return delta
  104. def GammaCalculator(context,S):
  105. current_date=context.current_dt.date()
  106. Tau=(g.maturity-current_date).days+1
  107. d1=(np.log(S/(g.S0*g.K))+(g.rf+g.sigma**2/2)*(Tau/g.YearDay))\
  108. /(g.sigma*np.sqrt(Tau/g.YearDay))
  109. gamma=norm.pdf(d1)/(S*g.sigma*np.sqrt(Tau/g.YearDay))
  110. return gamma
  111. def WhalleyWilmottThrehold(context,S):
  112. current_date=context.current_dt.date()
  113. risktolerance=5
  114. tradingcost=0.00055
  115. Tau=(g.maturity-current_date).days+1
  116. gamma=GammaCalculator(context,S)
  117. a=exp(-g.rf*Tau/g.YearDay)*tradingcost*S*gamma**2
  118. wwt=(3.0/2.0*a/risktolerance)**(1.0/3.0)
  119. return wwt