作者:量化投资学
题图:量化投资学微信公众号
在上一篇文章《ICU均线(上):使用稳健回归方法,突破传统均线》中,我们参考中泰证券的研报《“ICU均线”下的择时策略:“均线”才是绝对收益利器?》,介绍了一种基于稳健回归算法的新型均线——ICU均线,它能够更好地处理异常值,提供更稳健的趋势信号,并且具有更快的反应速度和更高的稳健性。本文以沪深300指数为例,介绍如何用Python实现ICU均线,并观察用ICU均线来进行择时的效果。
一、获取基础数据
1. 导入需要的库
# 导入需要使用的库
import akshare as ak
import pandas as pd
import numpy as np
# 在matplotlib绘图中显示中文和负号
import matplotlib.pyplot as plt
import matplotlib as mpl
mpl.rcParams['font.family'] = 'STKAITI' # 中文字体'STKAITI'
plt.rcParams['axes.unicode_minus'] = False # 解决坐标轴负数的负号显示问题
# 关闭警告信息
import warnings
warnings.filterwarnings('ignore')
2. 从AKShare数据源获取沪深300指数的数据
关于AKShare的使用,可以参看后附的文章《如何用AKShare获取金融数据》。AKShare的接口有时会有变动,如果获取数据出错请参考AKShare的官网解决。
# 获取指数数据
index_code = 'sh000300'
start_date = pd.to_datetime('2005-01-01')
end_date = pd.to_datetime('2023-12-31')
price_df = ak.stock_zh_index_daily(symbol=index_code)
price_df['date'] = pd.to_datetime(price_df['date'])
price_df = price_df[(price_df['date']>=start_date) & (price_df['date']<=end_date)]
price_df = price_df.sort_values('date').set_index('date')
上述代码用AKShare的stock_zh_index_daily()接口获取沪深300指数从2005年到2023年的行情数据。数据格式如下:
二、计算ICU均线
1. 计算重复中位数回归的斜率和截距
在《ICU均线(上):使用稳健回归方法,突破传统均线》中,我们介绍了ICU均线的算法,ICU均线的计算采用了重复中位数回归方法。
重复中位数回归是一种稳健回归技术,它的计算方法是:先对每一对数据点计算斜率;再对所有数据点对的斜率取中位数,得到整体的回归斜率;然后根据回归斜率,对每一对数据点计算截距;最后对所有数据点的截距取中位数,得到整体的回归截距。重复中位数回归的函数如下:
def repeated_median_regression(x, y):
n = len(x)
slopes = []
# 计算所有点对的斜率
for i in range(n):
for j in range(i + 1, n):
if x[j] != x[i]:
slopes.append((y[j] - y[i]) / (x[j] - x[i]))
# 计算所有斜率的中位数
median_slope = np.median(slopes)
# 计算所有截距的中位数
intercepts = y - median_slope * x
median_intercept = np.median(intercepts)
return median_slope, median_intercept
上述函数中,参数x为回归的自变量(时间序列),参数y为回归的因变量(价格序列)。函数返回重复中位数回归方程的斜率和截距。
2. 用重复中位数回归计算ICU均线
得出回归方程的斜率和截距后,我们就可以构建回归直线方程,根据中位数回归计算出的回归系数 α 和 β,计算时间窗口 window 内的均线值。
def calculate_icu_ma(prices, window):
icu_ma = []
for i in range(len(prices)):
if i < window - 1:
icu_ma.append(np.nan) # 前window-1个点无法计算均线
else:
x = np.arange(window)
y = prices[i - window + 1:i + 1].values
slope, intercept = repeated_median_regression(x, y)
icu_ma.append(intercept + slope * (window - 1)) # 计算窗口最后一个点的均线值
return pd.Series(icu_ma, index=prices.index)
上述函数用于计算ICU均线,参数prices为价格序列(pandas Series);参数window为计算均线的滚动窗口大小。函数的返回值为ICU均线序列。
接下来我们可以用这个函数来计算ICU均线:
# 计算ICU均线
window = 10
price_df['icu_ma'] = calculate_icu_ma(price_df['close'], window)
上述代码以10日为滚动窗口来计算ICU均线。
三、根据ICU均线择时
1. 计算择时信号
择时规则为:当收盘价大于ICU均线值时开仓,反之则清仓。
# ICU均线择时信号:当日 close 值大于 icu_ma 值则开仓,否则清仓
timing_df = pd.DataFrame()
timing_df['icu择时'] = (price_df['close']>price_df['icu_ma']) * 1.
timing_df['不择时'] = 1.
在上述代码中,当策略开仓时,择时信号为1;当策略清仓时,择时信号为0。
2. 计算择时收益
# 计算指数每日的收益率
price_df['returns'] = price_df['close'].pct_change().shift(-1).fillna(0)
# 计算择时后的每日收益率
timing_ret = timing_df.mul(price_df['returns'], axis=0).dropna()
# 计算择时后的累计收益率
cumul_ret = (1 + timing_ret.fillna(0)).cumprod() - 1.
上述代码先计算指数的每日收益率,然后将日收益率和择时信号相乘,如果择时信号为1,则保留该日收益率;如果择时信号为0,则该日收益率为0。然后计算累计收益。关于各种收益的计算,可以参看后附的文章《一文讲清7种收益率的python实现》。
3. 可视化择时效果
# 可视化输出
cumul_ret.plot(figsize=(10, 6), title='ICU择时')
择时效果如下:
可以看到,ICU择时达到了不错的择时效果。但复现的效果不及研报,原研报中择时收益曲线的回撤很小,有可能加入了其他的过滤条件。
版权声明:文章版权归原作者所有,部分文章由作者授权本平台发布,若有其他不妥之处的可与小编联系。