量化投资模型策略深度研究(二)

0
回复
7173
查看
[复制链接]

196

主题

140

回帖

1444

积分

管理员

积分
1444
来源: 2019-7-18 06:43:17 显示全部楼层 |阅读模式
均值回复策略

    此策略的基本理论认为,价格围绕其价值中枢而上下波动,想捕捉到交易机会,只需要判断出这个中枢以及波动的方向便可以。统计套利是用的最多的均值回复策略,认为价格出现背离类似股票的价值终究会缩小到合理的区间范围。

配对交易示例

    前段时间听到国投电力和川投能源两只股票,这两个公司的主要资产是一家水电公司48%,52%的股份,两只股价常在两倍之间变动。

# 首先我们简单看下两只股票的走势

  1. import seaborn as sns
  2. import pandas as pd
  3. import matplotlib.pylab as pylab
  4. from CAL.PyCAL import font
  5. begin_date, end_date = '20130101', '20150514'
  6. ct,gt = '600674', '600886'
  7. ct = DataAPI.MktEqudAdjGet(ticker=ct, beginDate=begin_date, endDate=end_date)
  8. gt = DataAPI.MktEqudAdjGet(ticker=gt, beginDate=begin_date, endDate=end_date)

  9. liangtou =pd.DataFrame()
  10. liangtou['川投股价'] = ct.closePrice
  11. liangtou['国投股价'] = gt.closePrice
  12. liangtou['川投国投股价比例'] =  ct.closePrice / gt.closePrice
  13. liangtou.plot( figsize=(16,10))
  14. pylab.legend([u'川投股价',u'国投股价', u'川投国投股价比例'], prop=font)
复制代码


利用量化实验室的strategy模式,咱来编写一个策略

起始建仓: 全仓600886
起始日期: 2014-12-01
结束日期: 2015-05-14
起始资金: 10w
调仓频率: 1天
调仓信号: 川投能源收盘价/国投能源收盘价*100%-200% 之差如果大于1%, 卖出886买入774, 如果小于-1%,则卖出774买入886

  1. start = '2014-12-01'                      # 回测起始时间
  2. end = '2015-05-14'                        # 回测结束时间
  3. benchmark = '600886.XSHG'                   # 策略参考标准
  4. universe = ['600674.XSHG', '600886.XSHG']        # 证券池
  5. capital_base = 100000                      # 起始资金
  6. refresh_rate = 1                         # 调仓频率,即每 refresh_rate 个交易日执行一次 handle_data() 函数
  7. ct_stk, gt_stk = universe

  8. def initialize(account):                   # 初始化虚拟账户状态
  9.     pass

  10. def handle_data(account):                  # 每天执行一次
  11.    
  12.     if len(account.universe) < 2: # 有停牌的话, 就跳过.
  13.         return
  14.    
  15.     ct_price, gt_price = account.referencePrice[ct_stk], account.referencePrice[gt_stk]   
  16.     percent = int(100*ct_price/gt_price-100)
  17.    
  18.     #第一次, 满仓买入600886
  19.     if not account.valid_secpos:
  20.         order(gt_stk, capital_base/gt_price)
  21.         return

  22.     if percent>1 and account.secpos.get(ct_stk, 0): #买886, 卖774
  23.         amount = account.secpos.get(ct_stk, 0)
  24.         print account.current_date, '买886,数量:%s, 卖774,数量:%s' %(amount*ct_price/gt_price, amount)
  25.         order(ct_stk, -amount)
  26.         order(gt_stk, amount*ct_price/gt_price)
  27.         
  28.     elif percent<-1 and account.secpos.get(gt_stk, 0): #卖886, 买774
  29.         amount = account.secpos.get(gt_stk, 0)
  30.         print account.current_date, '卖886,数量:%s, 买774,数量:%s' %(amount, amount*ct_price/gt_price)
  31.         order(gt_stk, -amount)
  32.         order(ct_stk, amount*gt_price/ct_price)
复制代码


      
2014-12-30 00:00:00 卖886,数量:14500, 买774,数量:14087.0708474
2015-02-03 00:00:00 买886,数量:15354.1736134, 卖774,数量:14500
2015-05-05 00:00:00 卖886,数量:15300, 买774,数量:14963.0007675
2015-05-08 00:00:00 买886,数量:16311.5583561, 卖774,数量:15600

延伸研究《基于时间序列的协整关系的配对交易》

技术情绪型策略

    此类策略主要通过追踪投资者情绪相关指标来判断预期回报,如交易量、波动性指标和交易价格等。比如高频交易通过限价指令簿的形态来判断近期市场情绪。

基于期权PCR择时

    投资者情绪对于资产价格变动影响是很大的,特别是投资者情绪的转变对于资产价格短期运动变化的解释力相比系统因素而言更强。P/C比例和VIX指数是期权市场中最常用的两个情绪指标,它们的运用可参考方正金工2015-6-19的报告《恐慌OR乐观指数,VIX信号日内、日间大不同》和2015-6-26的报告《P/C比例,市场情绪及投资者结构的风向标》。

    本文是基于期权PCR指数的择时策略。

P/C作为市场情绪指标

计算方式

    P/C比例作为一种反向情绪指标,是看跌期权的成交量(成交额,持仓量等)与看涨期权的成交量(持仓量)的比值。

指标含义

    看跌期权的成交量可以作为市场看空力量多寡的衡量;
    看涨期权的成交量可以描述市场看多力量。

指标应用

    当P/C比例过小达到一个极端时,被视为市场过度乐观,此时市场将遏制原来的上涨趋势;
    当P/C比例过大到达另一个极端时,被视为市场过度悲观,此时市场可能出现反弹。

策略思路

比较交易日之前两日的PCR(Put Call Ratio)指数:

PCR上升时,市场恐慌情绪蔓延,卖出
PCR下降时,恐慌情绪有所舒缓,买入

注:国内唯一一只期权上证50ETF期权,跟踪标的为华夏上证50ETF(510050)基金

1. 计算历史PCR指数  


  1. from matplotlib import pylab
  2. import numpy as np
  3. import pandas as pd
  4. import DataAPI
  5. import seaborn as sns
  6. sns.set_style('white')



  7. def getHistDayOptions(var, date):
  8.     # 使用DataAPI.OptGet,拿到已退市和上市的所有期权的基本信息;
  9.     # 同时使用DataAPI.MktOptdGet,拿到历史上某一天的期权成交信息;
  10.     # 返回历史上指定日期交易的所有期权信息,包括:
  11.     # optID  varSecID  contractType  strikePrice  expDate  tradeDate  closePrice turnoverValue
  12.     # 以optID为index。
  13.     dateStr = date.toISO().replace('-', '')
  14.     optionsMkt = DataAPI.MktOptdGet(tradeDate = dateStr, field = [u"optID", "tradeDate", "closePrice", "turnoverValue"], pandas = "1")
  15.     optionsMkt = optionsMkt.set_index(u"optID")
  16.     optionsMkt.closePrice.name = u"price"
  17.    
  18.     optionsID = map(str, optionsMkt.index.values.tolist())
  19.     fieldNeeded = ["optID", u"varSecID", u'contractType', u'strikePrice', u'expDate']
  20.     optionsInfo = DataAPI.OptGet(optID=optionsID, contractStatus = [u"DE", u"L"], field=fieldNeeded, pandas="1")
  21.     optionsInfo = optionsInfo.set_index(u"optID")
  22.     options = concat([optionsInfo, optionsMkt], axis=1, join='inner').sort_index()
  23.     return options[options.varSecID==var]

  24. def calDayTurnoverValuePCR(optionVarSecID, date):
  25.     # 计算历史每日的看跌看涨期权交易额的比值
  26.     # PCR: put call ratio
  27.     options = getHistDayOptions(optionVarSecID, date)
  28.     call = options[options.contractType==u"CO"]
  29.     put  = options[options.contractType==u"PO"]
  30.     callTurnoverValue = call.turnoverValue.sum()
  31.     putTurnoverValue = put.turnoverValue.sum()
  32.     return 1.0 * putTurnoverValue / callTurnoverValue

  33. def getHistPCR(beginDate, endDate):
  34.     # 计算历史一段时间内的PCR指数并返回
  35.     optionVarSecID = u"510050.XSHG"
  36.     cal = Calendar('China.SSE')
  37.     dates = cal.bizDatesList(beginDate, endDate)
  38.     dates = map(Date.toDateTime, dates)
  39.     histPCR = pd.DataFrame(0.0, index=dates, columns=['PCR'])
  40.     histPCR.index.name = 'date'
  41.     for date in histPCR.index:
  42.         histPCR['PCR'][date] =  calDayTurnoverValuePCR(optionVarSecID, Date.fromDateTime(date))
  43.     return histPCR

  44. def getDayPCR(date):
  45.     # 计算历史一段时间内的PCR指数并返回
  46.     optionVarSecID = u"510050.XSHG"
  47.     return calDayTurnoverValuePCR(optionVarSecID, date)
  48.    



  49. secID = '510050.XSHG'
  50. begin = Date(2015, 2, 9)
  51. end = Date(2015, 7, 30)

  52. getHistPCR(begin, end).tail()
复制代码





2. PCR指数与华夏上证50ETF基金的走势对比

  1. secID = '510050.XSHG'
  2. begin = Date(2015, 2, 9)
  3. end = Date(2015, 7, 30)

  4. # 历史PCR
  5. histPCR = getHistPCR(begin, end)

  6. # 华夏上证50ETF
  7. etf = DataAPI.MktFunddGet(secID, beginDate=begin.toISO().replace('-', ''), endDate=end.toISO().replace('-', ''), field=['tradeDate', 'closePrice'])
  8. etf['tradeDate'] = pd.to_datetime(etf['tradeDate'])
  9. etf = etf.set_index('tradeDate')


  10. font.set_size(12)
  11. pylab.figure(figsize = (16,8))

  12. ax1 = histPCR.plot(x=histPCR.index, y='PCR', style='r')
  13. ax1.set_xlabel(u'日期', fontproperties=font)
  14. ax1.set_ylabel(u'PCR(%)', fontproperties=font)

  15. ax2 = ax1.twinx()
  16. ax2.plot(etf.index,etf.closePrice)
  17. ax2.set_ylabel(u'ETF Price', fontproperties=font)
复制代码







从上图可以看出,每次PC指标的上升都对应着标的价格的下挫

3. 基于PCR指数的择时策略示例
  1. start = datetime(2015, 2, 9) # 回测起始时间
  2. end  = datetime(2015, 7, 31) # 回测结束时间
  3. benchmark = '510050.XSHG'     # 策略参考标准
  4. universe = ['510050.XSHG'] # 股票池
  5. capital_base = 100000     # 起始资金
  6. commission = Commission(0.0,0.0)

  7. longest_history = 1
  8. histPCR = getHistPCR(start, end)

  9. def initialize(account): # 初始化虚拟账户状态
  10.     account.fund = universe[0]

  11. def handle_data(account):             # 每个交易日的买入卖出指令
  12.     hist = account.get_history(longest_history)
  13.     fund = account.fund

  14.      #  获取回测当日的前一天日期
  15.     dt = Date.fromDateTime(account.current_date)
  16.     cal = Calendar('China.IB')
  17.     lastTDay = cal.advanceDate(dt,'-1B',BizDayConvention.Preceding)            #计算出倒数第一个交易日
  18.     lastLastTDay = cal.advanceDate(lastTDay,'-1B',BizDayConvention.Preceding)  #计算出倒数第二个交易日
  19.     last_day_str = lastTDay.strftime("%Y-%m-%d")
  20.     last_last_day_str = lastLastTDay.strftime("%Y-%m-%d")
  21.    
  22.     # 计算买入卖出信号
  23.     try:
复制代码







基于PCR指数上升时空仓、下降时进场的策略来买卖标的,可以比较有效地降低标的大跌的风险





回复

使用道具 举报

您需要登录后才可以回帖 登录 | 免费注册
关注微信