RSRS阻力支撑相对强度策略
一、阻力支撑相关概念
阻力位又称压力位,是指价格上涨到某个价位附近时,价格停止上涨甚至回落;其指指标价格上涨时可能遇到的压力,即交易者认为卖方力量开始反超买方,从而价格难以继续上涨或从此回调下跌的价位;支撑位则是交易者认为买方力量开始反超卖方,从而止跌或反弹上涨的价位。
常见的确定阻力支撑位的方法有,布林带上下轨突破策略(突破上轨建仓买入,突破下轨卖出平仓)和均线策略(如超过20日均线建仓买入,低于20日均线卖出平仓)。然而,布林带突破策略在震荡期间出现了持续亏损,均线策略交易交易成本巨大,且在震荡期间的回撤很大。
二、阻力支撑相对强度(RSRS)
阻力支撑相对强度(Resistance Support Relative Strength, RSRS)是另一种阻力位与支撑位的运用方式,它不再把阻力位与支撑位当做一个定值,而是看做一个变量,反应了交易者对目前市场状态顶底的一种预期判断。
我们按照不同市场状态分类来说明支撑阻力相对强度的应用逻辑:
1.市场在上涨牛市中:
如果支撑明显强于阻力,牛市持续,价格加速上涨
如果阻力明显强于支撑,牛市可能即将结束,价格见顶
2.市场在震荡中:
如果支撑明显强于阻力,牛市可能即将启动
如果阻力明显强于支撑,熊市可能即将启动
3.市场在下跌熊市中:
如果支撑明显强于阻力,熊市可能即将结束,价格见底
如果阻力明显强于支撑,熊市持续,价格加速下跌
每日最高价和最低价是一种阻力位与支撑位,它是当日全体市场参与者的交易行为所认可的阻力与支撑。一个很自然的想法是建立最高价和最低价的线性回归,并计算出斜率。即:
high=α+β·low+ϵ,ϵ∼N(0,δ2)
当斜率值很大时,支撑强度大于阻力强度。在牛市中阻力渐小,上方上涨空间大;在熊市中支撑渐强,下跌势头欲止。
当斜率值很小时,阻力强度大于支撑强度。在牛市中阻力渐强,上涨势头渐止;在熊市中支撑渐送,下方下跌空间渐大。
可参考光大研究报告。
三、阻力支撑相对强度(RSRS)指标择时策略
第一种方法是直接将斜率作为指标值。当日RSRS斜率指标择时策略如下:
1、取前N日最高价与最低价序列。(N = 18)
2、将两个序列进行OLS线性回归。
3、将拟合后的 β值作为当日RSRS斜率指标值。
4、当RSRS斜率大于 Sbuy时,全仓买入,小于 Ssell时,卖出平仓。(Sbuy=1,Ssell=0.8)
由于市场处于不同时期时,斜率的均值有比较大的波动。因此,直接采用斜率均值作为择时指标并不太合适。我们尝试下面的方法。
第二种方法是在斜率基础上进行标准化,取标准分作为指标值。RSRS斜率标准分指标择时策略如下:
1、取前M日的RSRS斜率时间序列。(M = 600)
2、计算当日RSRS斜率的标准分 RSRSstd:
RSRSstd=RSRS−μMσM
其中 μM 为前M日的斜率均值,σM为前M日的标准差。
3、若 RSRSstd大于 Sbuy,则全仓买入;若 RSRSstd小于 Ssell,则卖出平仓。(Sbuy=0.7,Ssell=−0.7)
注:benchmark和标的股票均为沪深300指数,尝试N取自10-30,M取自400-800,发现N=18,M=600时收益率最高。
N,M,Sbuy 的取值范围:18,252,0.6 , 或者:16,300,0.7
该策略从2010-01-01至2017-12-15,开平仓35次,总收益186.67%,年化收益14.58%,胜率0.556,盈亏比4.568,最大回撤20.031%。
# 导入函数库
import statsmodels.api as sm
# 初始化函数,设定基准等等
def initialize(context):
# 设定上证指数作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 输出内容到日志 log.info()
log.info('初始函数开始运行且全局只运行一次')
# 过滤掉order系列API产生的比error级别低的log
# log.set_level('order', 'error')
### 股票相关设定 ###
# 股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱
set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
## 运行函数(reference_security为运行时间的参考标的;传入的标的只做种类区分,因此传入'000300.XSHG'或'510300.XSHG'是一样的)
# 开盘前运行
run_daily(before_market_open, time='before_open', reference_security='000300.XSHG')
# 开盘时运行
run_daily(market_open, time='open', reference_security='000300.XSHG')
# 收盘后运行
run_daily(after_market_close, time='after_close', reference_security='000300.XSHG')
# 设置RSRS指标中N, M的值
g.N = 18
g.M = 600
g.init = True
# 要操作的股票:平安银行(g.为全局变量)
g.security = '000300.XSHG'
# 买入阈值
g.buy = 0.7
g.sell = -0.7
g.ans = []
# 计算2005年1月5日至回测开始日期的RSRS斜率指标
prices = get_price(g.security, '2005-01-05', context.previous_date, '1d', ['high', 'low'])
highs = prices.high
lows = prices.low
for i in range(len(highs))[g.N:]:
data_high = highs.iloc[i-g.N+1:i+1]
data_low = lows.iloc[i-g.N+1:i+1]
X = sm.add_constant(data_low)
model = sm.OLS(data_high,X)
results = model.fit()
# print("params is :",results.params)
# print("params.low is:",results.params['low'])
g.ans.append(results.params['low'])
## 开盘前运行函数
def before_market_open(context):
# 输出运行时间
log.info('函数运行时间(before_market_open):'+str(context.current_dt.time()))
## 开盘时运行函数
def market_open(context):
log.info('函数运行时间(market_open):'+str(context.current_dt.time()))
security = g.security
# 取得当前的现金
cash = context.portfolio.available_cash
# 填入各个日期的RSRS斜率值
security = g.security
if g.init:
g.init = False
else:
# RSRS斜率指标定义
prices = attribute_history(security, g.N, '1d', ['high', 'low'])
highs = prices.high
lows = prices.low
X = sm.add_constant(lows)
model = sm.OLS(highs, X)
beta = model.fit().params[1]
g.ans.append(beta)
# 计算标准化的RSRS指标
# 计算均值序列
section = g.ans[-g.M:]
# 计算均值序列
mu = np.mean(section)
# 计算标准化RSRS指标序列
sigma = np.std(section)
zscore = (section[-1]-mu)/sigma
# 如果上一时间点的RSRS斜率大于买入阈值, 则全仓买入
if zscore > g.buy:
# 记录这次买入
log.info("标准化RSRS斜率大于买入阈值, 买入 %s" % (security))
# 用所有 cash 买入股票
order_value(security, cash)
# 如果上一时间点的RSRS斜率小于卖出阈值, 则空仓卖出
elif zscore < g.sell and context.portfolio.positions[security].closeable_amount > 0:
# 记录这次卖出
log.info("标准化RSRS斜率小于卖出阈值, 卖出 %s" % (security))
# 卖出所有股票,使这只股票的最终持有量为0
order_target(security, 0)
## 收盘后运行函数
def after_market_close(context):
log.info(str('函数运行时间(after_market_close):'+str(context.current_dt.time())))
#得到当天所有成交记录
trades = get_trades()
for _trade in trades.values():
log.info('成交记录:'+str(_trade))
log.info('一天结束')
log.info('##############################################################')