作者:量化投资学
题图:量化投资学微信公众号
在上篇文章《低延迟趋势线择时:解决传统均线滞后问题的新策略(上)》中我们介绍了低延迟趋势线(LLT)择时的思路。低延迟趋势线(Low-Lag Trendline,简称LLT)是一种基于信号处理理论构建的技术指标,旨在提供比传统移动平均线(MA)更低的延迟和更好的趋势跟踪能力。LLT的设计目的是改善移动平均线在捕捉市场趋势时存在的时滞问题,使得趋势跟踪更加及时和准确。
本文用一个具体的例子说明如何用LLT进行择时。我们以上证指数为例,计算上证指数的LLT,然后根据LLT的趋势对上证指数进行择时,观察择时效果。
一、获取基础数据
1. 导入需要的库
# 导入需要使用的库
import akshare as ak
import pandas as pd
import numpy as np
import pandas_ta as ta
# 在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数据源获取上证指数的数据
关于AKShare的使用,可以参看后附的文章《如何用AKShare获取金融数据》。AKShare的接口有时会有变动,如果获取数据出错请参考AKShare的官网解决。
# 获取上证指数数据
index_code = 'sh000001'
start_date = pd.to_datetime('2014-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']).dt.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接口获取上证指数的行情数据保存到一个名为"price_df"的DataFrame中,并选取'2014-01-01'至'2023-12-31'这10年的数据作为本例的样本数据。
3. 计算每日的收益率
# 计算每日的收益率
price_df['returns'] = price_df['close'].pct_change().shift(-1).fillna(0)
上述代码用pct_change()函数计算每日的收益率。
二、计算低延迟趋势线LLT
1. 定义LLT的计算函数
在上篇文章《低延迟趋势线择时:解决传统均线滞后问题的新策略(上)》中,我们介绍了LLT指标的构造方法。LLT通过一个二阶低通滤波器来处理信号,二阶低通滤波器可以更有效地保留低频信号(即趋势信息),同时减少高频噪声(即短期波动)和延迟。LLT指标的计算公式如下(可点击图片放大):
根据以上公式,LLT的Python代码如下:
def get_llt(prices: pd.Series, alpha: float) -> pd.Series:
llt = pd.Series(index=prices.index, dtype='float64')
# 需要至少两个价格点来计算LLT
if len(prices) < 2:
return prices
# 初始化LLT的前两个值
llt[0] = prices[0]
llt[1] = prices[1]
# 使用给定的公式计算接下来的LLT值
for t in range(2, len(prices)):
llt[t] = ((alpha - alpha**2 / 4) * prices[t] +
(alpha**2 / 2) * prices[t-1] -
(alpha - 3 * alpha**2 / 4) * prices[t-2] +
2 * (1 - alpha) * llt[t-1] -
(1 - alpha)**2 * llt[t-2])
return llt
这个函数接受一个 pd.Series 对象 prices 作为价格时间序列输入,并使用 alpha 参数作为平滑因子来计算LLT。函数的输出也是一个 pd.Series 对象,为计算出的LLT的时间序列值。
函数先初始化LLT的前两个值,这是因为LLT的计算需要前两个时间点的数据。接下来,函数进入一个循环,从第三个数据点开始,按照公式来递归计算LLT的值。这个公式结合了当前价格 prices[t]、前两个价格 prices[t-1] 和 prices[t-2],以及LLT的前两个已计算值 llt[t-1] 和 llt[t-2]。
2. 计算LLT序列
# 计算LLT
d = 60 # 天数
alpha = 2 / (d + 1)
price_df['LLT'] = get_llt(price_df['close'], alpha)
计算LLT需要输入2个参数:价格时间序列 price_df['close'] 和 alpha。在《低延迟趋势线择时:解决传统均线滞后问题的新策略(上)》中我们提到,α参数与 计算天数d有如下关系: α = 2 / (d + 1)。计算天数越多,ɑ越小,延迟越高,平滑性越好。在本例中我们取计算天数为60天。
3. 将 LLT 序列可视化输出
为了观察 LLT 的是否具备低延迟的效果,我们计算了同样天数的均线作为对比,然后画出价格曲线、均线和LLT曲线。
# 比较:计算均线
price_df['均线'] = ta.sma(price_df['close'], length=d, talib=False)
# 可视化输出
price_df[['close', 'LLT','均线']].plot(figsize=(10, 6))
结果如下:
从上图可以看到,LLT曲线和均线都起到了平滑价格的作用,而且LLT曲线的延迟明显小于均线,对价格的跟随更紧密,达到了LLT曲线低延迟的效果。
三、使用 LLT 进行择时
1. 计算择时信号
择时信号的计算方法很多,在《低延迟趋势线择时:解决传统均线滞后问题的新策略(上)》中介绍了多种择时信号的计算方法,在本例中,我们选择的择时信号为当日LLT值大于昨日LLT值时开仓,反之清仓。
# 择时信号:当日LLT值大于昨日则开仓,否则清仓
timing_df = (price_df[['LLT']].diff()>0) * 1.
timing_df['不择时'] = 1.
上述代码通过 price_df[['LLT']].diff() 计算LLT的逐日差异,即当日LLT值与前一日LLT值的差。判断这个差是否大于0,如果是,表示价格上升的趋势,应该开仓买入;如果否,则表示价格下跌趋势,应该清仓卖出。布尔值与数字1相乘(* 1.)将布尔值转换为整数0或1,这样信号为1表示开仓,信号为0表示清仓。
代码在 timing_df 中添加了一个列 '不择时',并将其所有值设定为1。这表示一个基准:始终保持开仓状态,不考虑择时。
2. 计算择时收益
# 计算择时和不择时的每日收益率
timing_ret = timing_df.mul(price_df['returns'], axis=0)
# 计算累计收益率
cumul_ret = (1 + timing_ret.fillna(0)).cumprod() - 1.
上述代码首先计算每日收益率。它使用 mul() 方法将 timing_df 中的信号与 price_df['returns'] 中的每日收益率相乘。如果择时信号为1,则保留当日收益;如果择时信号为0,则当日收益为0。最后使用 cumprod() 方法来计算每日收益的累计乘积,得出累计收益。
关于各种收益的计算,可以参看后附的文章《一文讲清7种收益率的python实现》。
3. 可视化输出择时效果
# 可视化输出
cumul_ret.plot(figsize=(10, 6), title='LLT择时')
结果如下:
从上图可以看出,相比于原指数曲线,LLT 择时达到了一定的效果,提高了收益率。
本例并未对模型的参数进行优化,大家可以尝试其他的LLT参数(即alpha参数)和LLT择时信号的计算方法,来比较不同方案下LLT择时的效果。
版权声明:文章版权归原作者所有,部分文章由作者授权本平台发布,若有其他不妥之处的可与小编联系。