量化交易策略——相对OBV指标策略

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

95

主题

18

回帖

515

积分

高级会员

积分
515
来源: 2019-8-24 11:37:34 显示全部楼层 |阅读模式
      没有一个指标是完全适用任何时候的,本文并不是提供一种绝对赚钱的策略,有绝对盈利的点,估计也没人拿出来分享,宗旨还是提供一种思路,共同学习。


    OBV指标是葛兰碧于20世纪60年代提出的,并被广泛使用。该指标通过统计成交量变动的趋势来推测股价趋势。OBV以“N”字型为波动单位,并且由许许多多“N”型波构成了OBV的曲线图,对一浪高于一浪的“N”型波,称其为“上升潮”(UP TIDE),至于上升潮中的下跌回落则称为“跌潮”(DOWN FIELD)。OBV能量潮指标是成交量方面研究中相当重要的分析指标之一。1、当股价上升而OBV线下降,表示买盘无力,股价可能会回跌。2、股价下降时而OBV线上升,表示买盘旺盛,逢低接手强股,股价可能会止跌回升。


    其计算公式如下:

cl190824001.jpg



其中:

sign=+1 今日vol>昨日vol;

sign=-1 今日vol<昨日vol;

sign=0 今日vol==昨日vol。


    原力(相对OBV)

    定义相对OBV为:

cl190824002.jpg

n为时间参数。


    如相对成交量小于下阀值,则为空头信号;如相对成交量大于上阀值,则为多头信号;如相对成交量在上下阀值之间,则为空仓信号,以上是基于相对成交量,给出的多空信号判断。


    下图给出了在上下阀值均为 0.5 时,上证综指的多空信号判断结果,其中1代表多头信号, -1代表空头信号。

cl190824003.jpg

原力测试


1.在本策略中不存在卖空,所以当Force等于0或-1时空仓;Force等于1时,开多仓。


2.并未写成多股票的版本,只验证了单只股票。


3.下图为开启大盘止损之后的回测图,分享的回测则为未开启大盘止损的回测图。


cl190824004.jpg cl190824005.jpg cl190824006.jpg cl190824007.jpg cl190824008.jpg cl190824009.jpg



源码:



  1. mport talib
  2. from datetime import timedelta, date
  3. import numpy as np

  4. def Force(obv,n):
  5. min_obv = min(obv[-n:-1])
  6. max_obv = max(obv[-n:-1])
  7. r_volume = (obv[-1] - min_obv)/(max_obv - min_obv)
  8. return r_volume
  9. # 600307.XSHG 601988.XSHG

  10. def initialize(context):
  11.     # g.security = get_index_stocks('000300.XSHG')
  12.     g.security = ['600307.XSHG']
  13.     set_universe(g.security)
  14.     set_benchmark('600307.XSHG')
  15.     set_commission(PerTrade(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
  16.     set_slippage(PriceRelatedSlippage())
  17.     g.r_volume_data = 0
  18.     g.type = []
  19.     g.one_day = timedelta(days = 1)
  20.     g.start = context.current_dt.date() - 30*g.one_day

  21. def before_trading_start(context):
  22.     security = g.security
  23.     start = g.start
  24.     end = context.current_dt.date() - g.one_day
  25.     df = get_price(security[-1], start_date=start, end_date=end, frequency='daily', fields=['close','volume','factor'])
  26.     # 剔除停盘数据
  27.     df[df['volume']==0] = np.nan
  28.     df = df.dropna()
  29.     # 回复原始价格
  30.     df['close'] = df['close']/df['factor']
  31.     # 求obv值
  32.     obv = talib.OBV(df['close'].values,double(df['volume'].values))
  33.     # 求相对成交量
  34.     r_volume = Force(obv,10)
  35.    
  36.     # 确定买入卖出信号
  37.     if r_volume>0.5:
  38.         g.r_volume_data = 1
  39.         g.type.append(g.r_volume_data)
  40.     elif r_volume < -0.5:
  41.         g.r_volume_data = -1
  42.         g.type.append(g.r_volume_data)
  43.     else:
  44.         g.r_volume_data = 0
  45.         g.type.append(g.r_volume_data)

  46. def handle_data(context, data):
  47.    
  48.     # ## 止损
  49.     # d = dp_stoploss(kernel=2, n=10, zs=0.03)
  50.     # if d:
  51.     #     if len(context.portfolio.positions)>0:
  52.     #         for stock in list(context.portfolio.positions.keys()):
  53.     #             order_target(stock, 0)
  54.     #     return
  55.    
  56.     security = g.security
  57.     Cash = context.portfolio.cash
  58.     if g.r_volume_data == 1:
  59.         # 买入
  60.         order_value(security[-1],Cash)
  61.     else:
  62.         # 卖出
  63.         order_target(security[-1],0)
  64.         
  65. def dp_stoploss(kernel=2, n=10, zs=0.03):
  66.     '''
  67.     方法1:当大盘N日均线(默认60日)与昨日收盘价构成“死叉”,则发出True信号
  68.     方法2:当大盘N日内跌幅超过zs,则发出True信号
  69.     '''
  70.     # 止损方法1:根据大盘指数N日均线进行止损
  71.     if kernel == 1:
  72.         t = n+2
  73.         hist = attribute_history('000300.XSHG', t, '1d', 'close', df=False)
  74.         temp1 = sum(hist['close'][1:-1])/float(n)
  75.         temp2 = sum(hist['close'][0:-2])/float(n)
  76.         close1 = hist['close'][-1]
  77.         close2 = hist['close'][-2]
  78.         if (close2 > temp2) and (close1 < temp1):
  79.             return True
  80.         else:
  81.             return False
  82.     # 止损方法2:根据大盘指数跌幅进行止损
  83.     elif kernel == 2:
  84.         hist1 = attribute_history('000300.XSHG', n, '1d', 'close',df=False)
  85.         if ((1-float(hist1['close'][-1]/hist1['close'][0])) >= zs):
  86.             return True
  87.         else:
  88.             return False
复制代码



回复

使用道具 举报

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