首页 > 其他分享 >RSRS择时指标的150倍计算加速(有代码)

RSRS择时指标的150倍计算加速(有代码)

时间:2024-07-15 22:25:20浏览次数:17  
标签:RSRS 150 window 择时 beta np array numpy

文章来源于公众号:Logan投资

往期精选文章:

因子计算的1000倍加速

二级:手搓的择时指增

三因子择时策略

年入200w的鹅养殖基地

一级:轮胎行业的研究

二级:最近思考的量化指标再挖掘

前一篇推文中,介绍了用numpy加速rolling计算因子的方法。不过演示示例本身其实完全不需要apply,完全可以rolling.mean / rolling.std 来计算夏普,但是我展示的只是个思想,毕竟用rolling.apply去计算其他复杂的因子还是很慢的,所以在本文我尝试了用numpy去加速计算一个前几年较为火热的择时因子RSRS右偏标准分因子,再来做一个实例。

最终结果比网上公布的代码快了150+倍!!!

指标是基于光大证券研报《基于阻力支撑相对强度(RSRS)的市场择时》,给出了RSRS斜率指标择时,以及在斜率基础上的标准化指标择时策略。

阻力支撑相对强度(Resistance Support Relative Strength, RSRS)是另一种阻力位与支撑位的运用方式,它不再把阻力位与支撑位当做一个定值,而是看做一个变量,反应了交易者对目前市场状态顶底的一种预期判断。

其他因子的逻辑不多介绍了,大家可以去看这里

聚宽在知乎的文章:https://zhuanlan.zhihu.com/p/33501881

而在聚宽量化社区里也开源了RSRS的计算代码:

具体网址:

https://www.joinquant.com/view/community/detail/bec17e308647a2160ee1aeeac3a0c40c?type=1

原始RSRS计算代码如下:

import rqdatac as rq
from tqdm import tqdm
rq.init('账号', '密码')
data = rq.get_price('510330.XSHG', '2023-01-01','2024-01-01', frequency='30m')

def RSRS(low,high, regress_window: int,
         zscore_window: int, array: bool = False):
    """
    :param
    """

    high_array = high
    low_array = low

    highs = copy.deepcopy(high_array)
    lows = copy.deepcopy(low_array)
    rsrs_beta = []
    rsrs_rightdev = []
    zscore_rightdev = []

    N = regress_window
    M = zscore_window

    for i in range(len(highs)):
        try:
            data_high = highs[i - N + 1:i + 1]
            data_low = lows[i - N + 1:i + 1]
            X = sm.add_constant(data_low)
            model = sm.OLS(data_high, X)

            results = model.fit()
            beta = results.params[1]
            r2 = results.rsquared

            rsrs_beta.append(beta)
            rsrs_rightdev.append(r2)

            if len(rsrs_beta) < M:
                zscore_rightdev.append(0)
            else:
                section = rsrs_beta[-M:]
                mu = np.mean(section)
                sigma = np.std(section)
                zscore = (section[-1] - mu) / sigma
                # 计算右偏RSRS标准分
                zscore_rightdev.append(zscore * beta * r2)

        except:
            rsrs_beta.append(0)
            rsrs_rightdev.append(0)
            zscore_rightdev.append(0)

    if array:
        return zscore_rightdev
    else:
        return zscore_rightdev[-1]
test = []
for i in tqdm(range(10)):
    start = time.time()
    ddaa = RSRS(data.low, data.high, 18, 600,array=True)
    end = time.time()
    t = end - start
    test.append(t)
print(f'原始rsrs代码运行平均用时:{np.mean(test)}')

根据在聚宽网上的代码,用原始的代码计算RSRS并记录运行了10次的平均运算时间。

可以看到用原始代码运行的话平均需要7.89秒(参数为N=18,M=600)

这是仅对于一个股票计算的,若是根据RSRS在3000只票里选股就要计算很多次,进而花费时间大概是6.575个小时,这对于日频策略来说也够呛了,对于高频一点的策略或者平时的因子分析研究中更不用说了,还是很耗费时间的。

所以接下来上神器,numpy!

思想是用numpy矩阵运算实现滚动窗口的批量线性回归和指标计算。代码如下:

import numpy as np

from numpy.lib.stride_tricks import as_strided as strided

def rolling_window(a:np.array, window: int):
    '生成滚动窗口,以三维数组的形式展示'
    shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
    strides = a.strides + (a.strides[-1],)
    return strided(a, shape=shape, strides=strides)

def numpy_rolling_regress(x1, y1, window: int=18, array: bool=False):
    '在滚动窗口内进行,每个矩阵对应进行回归'
    x_series = np.array(x1)
    y_series = np.array(y1)
    # 创建一个一维数组
    dd = x_series
    x = rolling_window(dd, window)
    yT = rolling_window(y_series, window)
    y = np.array([i.reshape(window, 1) for i in yT])
    ones_vector = np.ones((1, x.shape[1]))
    XT = np.stack([np.vstack([ones_vector, row]) for row in x])  #加入常数项
    X = np.array([matrix.T for matrix in XT])  #以行数组表示
    reg_result = np.linalg.pinv(XT @ X) @ XT @ y   #线性回归公示

    if array:
        return reg_result
    else:
        frame = pd.DataFrame()
        result_const = np.zeros(x_series.shape[0])
        const = reg_result.reshape(-1, 2)[:,0]
        result_const[-const.shape[0]:] = const
        frame['const'] = result_const
        frame.index = x1.index
        for i in range(1, reg_result.shape[1]):

            result = np.zeros(x_series.shape[0])
            beta = reg_result.reshape(-1, 2)[:,i]
            result[-beta.shape[0]:] = beta
            frame[f'factor{i}'] = result
        return frame

def numpy_rsrs(low:pd.Series, high:pd.Series, N:int=18, M:int=600):
    beta_series = numpy_rolling_regress(low, high, window=N, array=True)
    beta = beta_series.reshape(-1, 2)[:,1]

    beta_rollwindow = rolling_window(beta, M)
    beta_mean = np.mean(beta_rollwindow, axis=1)
    beta_std = np.std(beta_rollwindow, axis=1)
    zscore = (beta[M-1:] - beta_mean) / beta_std
    return zscore

test = []
for i in tqdm(range(50)):
    start = time.time()
    numpy_rsrs(data.low, data.high)
    end = time.time()
    test.append(end - start)
print(f'numpy加速后的rsrs代码运行平均用时:{np.mean(test)}')

这里的RSRS没有进行右偏处理,右偏RSRS在下文中

运行了50次的平均用时

可以看到平均运行了约0.05秒,足足快了157.8倍!!!!!

这个速度可能还不足以满足几千只股票的RSRS指标的计算,但是对于研究已经是极大的提速了。若限制1秒以内的延迟上限,再用上多进程multiprocessing,只能满足20~100只标的的RSRS指标的计算,但这也满足宽基指数的分钟级和小时级的择时策略了。

进阶一点就是考虑用DASK框架写成并发过程,用这个函数并发计算几千只股票的因子。

具体速度得看各位的电脑配置了

我就是个小小的破surface pro,16G内存

以上是RSRS计算的代码和过程。

而原版RSRS中还对其进行修正为RSRS右偏标准分,而我也复现了出来,搞了好一会儿的高等数学和线性代数。具体运行时间如下,为了减少rolling次数,所以我全部都写在了同一个函数里面。

为了展示运行结果的正确性,我挑出numpy加速后的RSRS右偏标准分最后100条数据和原始代码计算的RSRS右偏标准分进行了对比


蓝色粗线为原始的,覆盖在上面的红色细线是numpy进行计算的。可以看到完全一致,计算结果无误。

最后附上回测图,RSRS右偏标准分择时指标在近年回撤得比较厉害。

RSRS右偏标准分的代码有需要的朋友可以在公众号后台私信我“RSRS”即可。

标签:RSRS,150,window,择时,beta,np,array,numpy
From: https://blog.csdn.net/Edenfranx/article/details/140379005

相关文章

  • Day10(栈与队列) | 150. 逆波兰表达式求值 239. 滑动窗口最大值 347.前 K 个高频元
    150.逆波兰表达式求值给你一个字符串数组tokens,表示一个根据逆波兰表示法表示的算术表达式。请你计算该表达式。返回一个表示表达式值的整数。注意:有效的算符为'+'、'-'、'*'和'/'。每个操作数(运算对象)都可以是一个整数或者另一个表达式。两个整数之间的除法总是......
  • day11| 150. 逆波兰表达式求值 239. 滑动窗口最大值 347.前 K 个高频元素
    代码随想录算法训练营第十一天|150.逆波兰表达式求值239.滑动窗口最大值347.前K个高频元素Leetcode150.逆波兰表达式求值题目链接:https://leetcode.cn/problems/evaluate-reverse-polish-notation/description/题目描述:给你一个字符串数组tokens,表示一个根......
  • 「杂题乱刷2」CF1506E Restoring the Permutation
    duel到的。题目链接CF1506E解题思路有一个显然的性质就是这个序列的前缀最大值是单调不降的。于是我们就可以对于每个位置考虑还可以填哪些数,对于字典序最小的肯定填当时可填的最小数字,对于字典序最大的肯定填当时可填的最大数字,因为你可以通过填一个数的方式来满足要求,因此......
  • 24暑假算法刷题 | Day11 | LeetCode 150. 逆波兰表达式求值,239. 滑动窗口最大值,347.
    目录150.逆波兰表达式求值题目描述题解239.滑动窗口最大值题目描述题解347.前K个高频元素题目描述题解150.逆波兰表达式求值点此跳转题目链接题目描述给你一个字符串数组tokens,表示一个根据逆波兰表示法表示的算术表达式。请你计算该表达式。返回一个......
  • 关于力扣150题目——逆波兰表达式求值Java实现的三种解法
    题目介绍逆波兰表达式是一种后缀表达式,其运算符位于操作数之后。力扣150题目要求我们实现一个函数,计算给定逆波兰表达式的值。本文将介绍三种不同的Java实现方法来解决这个问题。解法一:使用栈这是最直观和常见的解法,使用栈来存储操作数,并在遇到运算符时从栈中弹出操作数......
  • Solution - Atcoder ARC150D Removing Gacha
    考虑到每次操作都比定会选上一个点,于是答案可以表示为每个点被选中的次数之和。即令\(c_i\)为\(i\)点被选中的次数,答案即为\(E(\sum\limits_{i=1}^nc_i)\)。根据期望的线性性,考虑把答案的\(E\)拆到每个\(c_i\)上,即变为\(\sum\limits_{i=1}^nE(c_i)\)的形式。......
  • 应用程序无法正常启动(0xc0150002)的解决思路
    背景介绍一测试朋友,因为重装了操作系统,然后之前的工具突然无法使用了。现象现象1现象2解决现象1很显然,缺少运行库。你如果安装了visualstudio,那么其安装目录下xxx\MicrosoftVisualStudio\2019\Professional\VC\Redist\MSVC会存在需要的运行库或者是运行库安装......
  • 3年阿里hk主机干房BGP仅需150元 5年270元,单月4.2元(大水管)
    首先需要说明的是这个神仙操作不是我原创的,我只是进行二次归纳进行再次恰饭。感谢各位大佬提供的购买思路,真是把规则研究透了。 结论完成本文全部操作后你将以150-270元获取3-5年的下述服务器(或者白嫖到底0元购获取1年),这个价格我感觉很划算了毕竟是大厂的BGP线路,而且三网拉直,2......
  • 手把手教你,利用机器学习模型,构建量化择时策略(附全流程代码)
    歌神演唱会人脸识别抓逃犯,阿尔法狗战胜人类围棋手,AI绘图《太空歌剧院》惊艳艺术博览会,ChatGPT一问解千愁~~~这些震撼成果的背后,都是人工智能在蓬勃发力。既然人工智能/机器学习这么厉害,在其他领域都取得了丰硕的成果和巨大的成功,那么是不是可以让计算机帮咱预测市场大盘、......
  • 复现网红阻力支撑指标RSRS,手把手教你构建大盘择时策略
    之前写过一篇利用RSRS指标做ETF轮动的文章,可能是因为回测绩效看起来还不错,其后就有不少小伙伴陆陆续续来询问,想不到还有那么多人关注,于是本期文章就想掰开了揉碎了唠唠RSRS,从数据获取、计算细节一直聊到策略构建,不藏着掖着,每一步都有对应代码。我当初关注到RSRS,是因为当时无......