|
没有一个指标是完全适用任何时候的,本文并不是提供一种绝对赚钱的策略,有绝对盈利的点,估计也没人拿出来分享,宗旨还是提供一种思路,共同学习。
OBV指标是葛兰碧于20世纪60年代提出的,并被广泛使用。该指标通过统计成交量变动的趋势来推测股价趋势。OBV以“N”字型为波动单位,并且由许许多多“N”型波构成了OBV的曲线图,对一浪高于一浪的“N”型波,称其为“上升潮”(UP TIDE),至于上升潮中的下跌回落则称为“跌潮”(DOWN FIELD)。OBV能量潮指标是成交量方面研究中相当重要的分析指标之一。1、当股价上升而OBV线下降,表示买盘无力,股价可能会回跌。2、股价下降时而OBV线上升,表示买盘旺盛,逢低接手强股,股价可能会止跌回升。
其计算公式如下:

其中:
sign=+1 今日vol>昨日vol;
sign=-1 今日vol<昨日vol;
sign=0 今日vol==昨日vol。
原力(相对OBV)
定义相对OBV为:

n为时间参数。
如相对成交量小于下阀值,则为空头信号;如相对成交量大于上阀值,则为多头信号;如相对成交量在上下阀值之间,则为空仓信号,以上是基于相对成交量,给出的多空信号判断。
下图给出了在上下阀值均为 0.5 时,上证综指的多空信号判断结果,其中1代表多头信号, -1代表空头信号。

原力测试
1.在本策略中不存在卖空,所以当Force等于0或-1时空仓;Force等于1时,开多仓。
2.并未写成多股票的版本,只验证了单只股票。
3.下图为开启大盘止损之后的回测图,分享的回测则为未开启大盘止损的回测图。

收益与风险






源码:
- import talib
- from datetime import timedelta, date
- import numpy as np
- def Force(obv,n):
- min_obv = min(obv[-n:-1])
- max_obv = max(obv[-n:-1])
- r_volume = (obv[-1] - min_obv)/(max_obv - min_obv)
- return r_volume
- # 600307.XSHG 601988.XSHG
- def initialize(context):
- # g.security = get_index_stocks('000300.XSHG')
- g.security = ['600307.XSHG']
- set_universe(g.security)
- set_benchmark('600307.XSHG')
- set_commission(PerTrade(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
- set_slippage(PriceRelatedSlippage())
- g.r_volume_data = 0
- g.type = []
- g.one_day = timedelta(days = 1)
- g.start = context.current_dt.date() - 30*g.one_day
- def before_trading_start(context):
- security = g.security
- start = g.start
- end = context.current_dt.date() - g.one_day
- df = get_price(security[-1], start_date=start, end_date=end, frequency='daily', fields=['close','volume','factor'])
- # 剔除停盘数据
- df[df['volume']==0] = np.nan
- df = df.dropna()
- # 回复原始价格
- df['close'] = df['close']/df['factor']
- # 求obv值
- obv = talib.OBV(df['close'].values,double(df['volume'].values))
- # 求相对成交量
- r_volume = Force(obv,10)
-
- # 确定买入卖出信号
- if r_volume>0.5:
- g.r_volume_data = 1
- g.type.append(g.r_volume_data)
- elif r_volume < -0.5:
- g.r_volume_data = -1
- g.type.append(g.r_volume_data)
- else:
- g.r_volume_data = 0
- g.type.append(g.r_volume_data)
- def handle_data(context, data):
-
- # ## 止损
- # d = dp_stoploss(kernel=2, n=10, zs=0.03)
- # if d:
- # if len(context.portfolio.positions)>0:
- # for stock in list(context.portfolio.positions.keys()):
- # order_target(stock, 0)
- # return
-
- security = g.security
- Cash = context.portfolio.cash
- if g.r_volume_data == 1:
- # 买入
- order_value(security[-1],Cash)
- else:
- # 卖出
- order_target(security[-1],0)
-
- def dp_stoploss(kernel=2, n=10, zs=0.03):
- '''
- 方法1:当大盘N日均线(默认60日)与昨日收盘价构成“死叉”,则发出True信号
- 方法2:当大盘N日内跌幅超过zs,则发出True信号
- '''
- # 止损方法1:根据大盘指数N日均线进行止损
- if kernel == 1:
- t = n+2
- hist = attribute_history('000300.XSHG', t, '1d', 'close', df=False)
- temp1 = sum(hist['close'][1:-1])/float(n)
- temp2 = sum(hist['close'][0:-2])/float(n)
- close1 = hist['close'][-1]
- close2 = hist['close'][-2]
- if (close2 > temp2) and (close1 < temp1):
- return True
- else:
- return False
- # 止损方法2:根据大盘指数跌幅进行止损
- elif kernel == 2:
- hist1 = attribute_history('000300.XSHG', n, '1d', 'close',df=False)
- if ((1-float(hist1['close'][-1]/hist1['close'][0])) >= zs):
- return True
- else:
- return False
复制代码
|
|