全方位斜率(下):掌握跨时间跨市场的趋势洞察

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)

       

这个复合指标的创新之处在于:

  1. 自适应性:根据市场波动性动态调整计算参数
  2. 动态权重:基于趋势一致性自动调整各时间框架的权重
  3. 综合性:整合了多个时间维度的信息

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

猜你喜欢

转载自blog.csdn.net/hoddy355/article/details/143336615