量化交易策略——相对OBV指标策略
没有一个指标是完全适用任何时候的,本文并不是提供一种绝对赚钱的策略,有绝对盈利的点,估计也没人拿出来分享,宗旨还是提供一种思路,共同学习。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.下图为开启大盘止损之后的回测图,分享的回测则为未开启大盘止损的回测图。
源码:
mport 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==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'])/float(n)
temp2 = sum(hist['close'])/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'])) >= zs):
return True
else:
return False
页:
[1]