4. 开发多维度斜率指标
随着我们对时间框架和市场关联性的理解加深,是时候将这些知识整合成一个更全面的分析工具了。在量化交易实践中,我发现将多个维度的斜率信息有机结合,能够提供更可靠的市场洞察。
4.1合短期、中期和长期斜率的复合指标
首先,让我们开发一个整合多个时间维度的复合指标:
class MultiTimeframeSlopeIndicator:
def __init__(self, timeframes={'short': '1h', 'medium': '4h', 'long': '1d'},
windows={'short': 10, 'medium': 20, 'long': 30}):
self.timeframes = timeframes
self.windows = windows
def _calculate_adaptive_slope(self, data, window):
"""
计算自适应斜率
参数:
data: pd.Series, 价格数据
window: int, 计算窗口大小
"""
if len(data) < window:
print(f"警告: 数据长度 {len(data)} 小于窗口大小 {window}")
return pd.Series(np.nan, index=data.index)
# 确保数据是连续的,没有缺失值
data = data.ffill().bfill()
# 计算波动率,使用简单标准差
volatility = data.rolling(window=window, min_periods=1).std()
slopes = pd.Series(np.nan, index=data.index)
# 使用向量化操作计算斜率
for i in range(window, len(data) + 1):
y = data.iloc[i-window:i].values
x = np.arange(window)
if len(y) == window:
slope, _ = np.polyfit(x, y, 1)
vol = volatility.iloc[i-1]
# 标准化斜率
slopes.iloc[i-1] = slope / vol if vol != 0 else slope
return slopes
def calculate_composite_slope(self, price_data):
"""
计算复合斜率指标
"""
# 初始化结果DataFrame
composite_slopes = pd.DataFrame(index=price_data.index)
price_data = price_data.ffill().bfill() # 确保价格数据连续
# 为每个时间框架计算斜率
for tf_name, tf in self.timeframes.items():
# 重采样数据
resampled = price_data.resample(tf).last()
resampled = resampled.ffill().bfill() # 确保重采样数据连续
window = self.windows[tf_name]
if len(resampled) > window:
# 计算斜率
slopes = self._calculate_adaptive_slope(resampled, window)
# 对齐到原始时间框架
aligned_slopes = slopes.reindex(price_data.index).ffill(limit=int(pd.Timedelta(tf) / pd.Timedelta('1H')))
composite_slopes[tf_name] = aligned_slopes
# 删除全部为NaN的行
composite_slopes = composite_slopes.dropna(how='all')
# 如果没有有效数据,返回NaN序列
if composite_slopes.empty:
return pd.Series(np.nan, index=price_data.index)
# 计算动态权重
weights = self._calculate_dynamic_weights(composite_slopes)
composite = self._weighted_composite(composite_slopes, weights)
return composite.reindex(price_data.index)
def _calculate_dynamic_weights(self, slopes_data):
"""
基于趋势一致性动态调整权重
参数:
slopes_data: DataFrame, 包含不同时间框架的斜率数据
"""
try:
# 使用新的方法处理NaN值
slopes_clean = slopes_data.ffill().bfill()
# 计算相关性矩阵
correlations = slopes_clean.corr()
# 计算每个时间框架的平均相关性
mean_corr = correlations.mean()
# 确保权重为正且和为1
weights = np.abs(mean_corr)
weights_sum = weights.sum()
if weights_sum > 0:
weights = weights / weights_sum
else:
# 如果所有权重都是0,使用均等权重
weights = pd.Series(1.0/len(slopes_data.columns), index=slopes_data.columns)
print("\n计算的权重:")
for tf, weight in weights.items():
print(f"{tf}: {weight:.3f}")
return weights
except Exception as e:
print(f"计算动态权重时出错: {e}")
# 返回均等权重
return pd.Series(1.0/len(slopes_data.columns), index=slopes_data.columns)
def _weighted_composite(self, slopes_data, weights):
"""
计算加权综合指标
参数:
slopes_data: DataFrame, 包含不同时间框架的斜率数据
weights: Series, 各时间框架的权重
"""
try:
# 使用新的方法处理NaN值
slopes_clean = slopes_data.ffill().bfill()
# 计算加权和
weighted_sum = pd.Series(0, index=slopes_clean.index)
for column in slopes_clean.columns:
weighted_sum += slopes_clean[column] * weights[column]
return weighted_sum
except Exception as e:
print(f"计算加权综合指标时出错: {e}")
return pd.Series(np.nan, index=slopes_data.index)
def visualize_results(price_data, composite_slopes, indicator, year=2024, month=9):
"""
可视化分析结果,先计算所有数据,然后只显示指定月份
"""
# 先计算所有时间的斜率
slopes_data = pd.DataFrame(index=price_data.index)
# 计算各时间框架的斜率
for tf_name, tf in indicator.timeframes.items():
resampled = price_data.resample(tf).last()
resampled = resampled.ffill().bfill()
window = indicator.windows[tf_name]
if len(resampled) > window:
slopes = indicator._calculate_adaptive_slope(resampled, window)
aligned_slopes = slopes.reindex(price_data.index).ffill()
slopes_data[tf_name] = aligned_slopes
# 在计算完所有数据后,选择指定月份的数据进行绘图
mask = (price_data.index.year == year) & (price_data.index.month == month)
selected_price = price_data[mask]
selected_slopes = slopes_data[mask]
selected_composite = composite_slopes[mask] if isinstance(composite_slopes, pd.Series) else None
# 创建图表
fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(15, 12), sharex=True)
# 创建数字索引
data_points = list(range(len(selected_price)))
# 绘制价格数据
ax1.plot(data_points, selected_price.values, label='Price', color='pink')
ax1.set_title(f'Price Data ({year}-{month:02d})')
ax1.grid(True)
ax1.legend()
# 绘制各时间框架的斜率
colors = {'short': 'red', 'medium': 'blue', 'long': 'green'}
for tf_name in slopes_data.columns:
ax2.plot(data_points, selected_slopes[tf_name].values,
label=f'{tf_name} Slope',
color=colors[tf_name],
linewidth=1)
ax2.set_title(f'Slopes by Timeframe ({year}-{month:02d})')
ax2.grid(True)
ax2.legend()
# 绘制复合斜率
if selected_composite is not None:
ax3.plot(data_points, selected_composite.values,
label='Composite Slope', color='red', linewidth=1)
ax3.set_title(f'Composite Slope ({year}-{month:02d})')
ax3.grid(True)
ax3.legend()
# 设置x轴标签为日期
num_ticks = min(20, len(data_points)) # 可以调整显示的刻度数量
tick_indices = np.linspace(0, len(data_points)-1, num_ticks, dtype=int)
tick_dates = selected_price.index[tick_indices].strftime('%Y-%m-%d')
ax3.set_xticks(tick_indices)
ax3.set_xticklabels(tick_dates, rotation=45)
# 调整布局
plt.tight_layout()
plt.show()
# 打印统计信息
print(f"\n{year}年{month}月斜率统计信息:")
print(selected_slopes.describe())
print("\n各时间框架的NaN数量:")
print(selected_slopes.isna().sum())
# 运行测试
if __name__ == "__main__":
visualize_results(price_data, composite_slopes, indicator, year=2024, month=9)
这个复合指标的创新之处在于:
- 自适应性:根据市场波动性动态调整计算参数
- 动态权重:基于趋势一致性自动调整各时间框架的权重
- 综合性:整合了多个时间维度的信息
4.2 考虑成交量的加权斜率
接下来,让我们在斜率计算中引入成交量因素:
def volume_weighted_slope(price_data, volume_data, window=30):
"""
计算成交量加权斜率
参数:
price_data: pd.Series, 价格数据
volume_data: pd.Series, 成交量数据
window: int, 计算窗口大小
"""
try:
# 确保数据对齐且没有缺失值
price_data = price_data.ffill().bfill()
volume_data = volume_data.ffill().bfill()
# 标准化成交量
normalized_volume = (volume_data - volume_data.rolling(window).mean()) / \
volume_data.rolling(window).std()
normalized_volume = normalized_volume.fillna(0) # 处理开始的NaN值
# 初始化结果序列
slopes = pd.Series(index=price_data.index)
slopes[:] = np.nan
# 循环计算斜率
for i in range(window, len(price_data)):
try:
y = price_data.iloc[i-window:i].values
x = np.arange(window)
w = normalized_volume.iloc[i-window:i].values
# 确保数据有效
if len(y) == window and len(w) == window and not np.any(np.isnan(y)) and not np.any(np.isnan(w)):
# 将权重限制在合理范围内
w = np.clip(w, -2, 2)
# 添加小的正数以避免零权重
w = np.abs(w) + 1e-8
try:
# 使用numpy的加权最小二乘
slope, _ = np.polyfit(x, y, 1, w=w)
slopes.iloc[i] = slope
except np.linalg.LinAlgError:
# 如果加权回归失败,尝试不加权的回归
try:
slope, _ = np.polyfit(x, y, 1)
slopes.iloc[i] = slope
except:
continue
except Exception as e:
print(f"计算第 {i} 个窗口的斜率时出错: {str(e)}")
continue
return slopes
except Exception as e:
print(f"计算成交量加权斜率时出错: {str(e)}")
return pd.Series(np.nan, index=price_data.index)
# 使用示例
def test_volume_weighted_slope():
"""
测试成交量加权斜率计算
"""
# 计算成交量加权斜率
slopes = volume_weighted_slope(prices, volumes, window=30)
# 合并数据并删除无效数据
valid_data = pd.concat([prices, volumes, slopes], axis=1)
valid_data.columns = ['Price', 'Volume', 'Slope']
valid_data = valid_data.dropna()
# 创建数字索引
data_points = list(range(len(valid_data)))
fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(15, 10), sharex=True)
# 绘制价格
ax1.plot(data_points, valid_data['Price'], 'r-', label='Price')
ax1.set_title('Price Data')
ax1.grid(True, linestyle='--', alpha=0.7)
ax1.legend()
# 绘制成交量
ax2.plot(data_points, valid_data['Volume'], 'g-', label='Volume')
ax2.set_title('Volume Data')
ax2.grid(True, linestyle='--', alpha=0.7)
ax2.legend()
# 绘制斜率
ax3.plot(data_points, valid_data['Slope'], 'r-', label='Volume-Weighted Slope')
ax3.set_title('Volume-Weighted Slope')
ax3.grid(True, linestyle='--', alpha=0.7)
ax3.legend()
# 设置x轴标签为日期
num_ticks = 10 # 可以调整这个数字来控制显示的刻度数量
tick_indices = np.linspace(0, len(data_points)-1, num_ticks, dtype=int)
tick_dates = valid_data.index[tick_indices].strftime('%Y-%m-%d')
ax3.set_xticks(tick_indices)
ax3.set_xticklabels(tick_dates, rotation=45)
plt.tight_layout()
plt.show()
return valid_data['Slope']
# 运行测试
if __name__ == "__main__":
test_volume_weighted_slope()
成交量加权的意义在于:
- 高成交量时段的价格变动获得更高权重
- 能够更好地识别真实的市场动力
- 帮助过滤虚假的价格波动
这些多维度指标的实际应用需要考虑很多因素,比如计算效率、信号延迟等。在我们的下一篇文章中,我们将详细探讨如何将这些指标转化为实际可交易的策略。
5. 实战示例:构建多时间框架、跨市场的斜率分析系统
在量化交易实践中,将理论转化为可操作的分析系统是一个关键挑战。让我们通过一个完整的实战案例,展示如何构建一个综合的斜率分析系统。
class ComprehensiveSlopeAnalyzer:
def __init__(self):
self.mtf_indicator = MultiTimeframeSlopeIndicator()
self.markets = {}
self.correlations = {}
def add_market_data(self, market_name, price_data, volume_data=None):
"""
添加市场数据
"""
self.markets[market_name] = {
'price': price_data,
'volume': volume_data,
'slopes': {}
}
def analyze_market(self, market_name):
"""
分析单个市场的多维度斜率
"""
market_data = self.markets[market_name]
# 计算多时间框架复合斜率
market_data['slopes']['composite'] = self.mtf_indicator.calculate_composite_slope(
market_data['price']
)
# 如果有成交量数据,计算成交量加权斜率
if market_data['volume'] is not None:
market_data['slopes']['volume_weighted'] = volume_weighted_slope(
market_data['price'],
market_data['volume']
)
def _calculate_trend_strength(self, composite_slope):
"""
计算趋势强度
"""
# 使用斜率的绝对值和持续性评估趋势强度
strength = pd.Series(index=composite_slope.index)
window = 20
for i in range(window, len(composite_slope)):
current_slopes = composite_slope.iloc[i - window:i]
# 计算斜率的一致性
direction_consistency = np.sign(curren