用Python构建筹码分布分析工具:从数据估算到交易决策

当你在交易软件上看到那些五彩斑斓的K线图时,是否曾好奇过背后隐藏的市场情绪?传统的技术分析往往只关注价格走势,却忽略了另一个关键维度——市场参与者的持仓成本分布。这就是筹码分析的价值所在,它能够揭示不同价格区间上投资者的盈亏状况,为我们提供更全面的市场视角。

1. 理解筹码分布的核心逻辑

筹码分布分析的核心在于估算市场上投资者在不同价格区间的持仓比例。由于我们无法获取每个投资者的实际持仓数据,只能通过成交量、换手率等公开信息进行合理估算。

1.1 筹码分布的基本原理

假设某只股票总流通量为1000万股:

  • 第一天平均成交价为10元,换手率为0%
  • 第二天换手率为20%,平均成交价为11元
  • 第三天换手率为30%,平均成交价为12元

那么第三天的筹码分布计算如下:

价格区间 计算公式 持仓量(万股)
10元 1000×(1-0.2)×(1-0.3) 560
11元 1000×0.2×(1-0.3) 140
12元 1000×0.3 300

这种估算方法基于一个合理假设:新成交的筹码会替代部分旧筹码,而未被替代的旧筹码则继续保留在原价格区间。

1.2 获利盘比例的计算

获利盘比例是指在当前价格下,持仓成本低于当前价格的筹码占总筹码的比例。计算这个比例需要:

  1. 确定当前价格
  2. 汇总所有低于当前价格的筹码量
  3. 计算其占总筹码的比例
def calculate_profit_ratio(chip_distribution, current_price):
    """
    计算获利盘比例
    
    参数:
    chip_distribution -- 字典,键为价格,值为对应持仓量
    current_price -- 当前价格
    
    返回:
    获利盘比例(0-1之间)
    """
    total_chips = sum(chip_distribution.values())
    profitable_chips = sum(amount for price, amount in chip_distribution.items() 
                          if price < current_price)
    return profitable_chips / total_chips if total_chips > 0 else 0

2. 构建Python筹码分析工具

现在,让我们将这些理论转化为实际的Python工具。我们将使用pandas进行数据处理,matplotlib进行可视化。

2.1 数据准备与预处理

首先需要获取以下数据:

  • 历史成交量
  • 历史成交额
  • 换手率数据
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

def prepare_data(stock_code, start_date, end_date):
    """
    准备基础数据
    
    参数:
    stock_code -- 股票代码
    start_date -- 开始日期
    end_date -- 结束日期
    
    返回:
    包含成交量、成交额、换手率的DataFrame
    """
    # 这里假设我们已经通过某种API获取了原始数据
    raw_data = get_market_data(stock_code, start_date, end_date)
    
    # 计算平均成交价格
    raw_data['avg_price'] = raw_data['amount'] / raw_data['volume']
    
    # 处理缺失值和异常值
    data = raw_data[raw_data['volume'] > 0].copy()
    data['turnover'] = data['turnover'].fillna(0)
    
    return data

2.2 筹码分布计算实现

基于前面的理论,我们可以实现筹码分布的计算:

def calculate_chip_distribution(data):
    """
    计算每日的筹码分布
    
    参数:
    data -- 包含成交量、换手率等信息的DataFrame
    
    返回:
    包含每日筹码分布的字典
    """
    chip_distributions = {}
    total_shares = 1.0  # 假设总流通量为1(比例表示)
    
    for i, row in data.iterrows():
        date = row.name
        avg_price = row['avg_price']
        turnover = row['turnover']
        
        if i == 0:
            # 第一天,所有筹码都在当日平均价
            chip_distributions[date] = {avg_price: total_shares}
        else:
            # 获取前一天的筹码分布
            prev_date = data.index[i-1]
            prev_dist = chip_distributions[prev_date].copy()
            
            # 计算新筹码分布
            new_dist = {}
            for price, amount in prev_dist.items():
                new_dist[price] = amount * (1 - turnover)
            
            # 添加今日新筹码
            new_dist[avg_price] = new_dist.get(avg_price, 0) + total_shares * turnover
            
            # 存储结果
            chip_distributions[date] = new_dist
    
    return chip_distributions

注意:实际应用中,总流通量应该使用实际的流通股本数据。这里使用1.0是为了简化计算,结果表示的是比例而非绝对数量。

3. 高级分析与可视化

有了基础的筹码分布数据后,我们可以进行更深入的分析和可视化。

3.1 动态获利盘比例分析

我们可以计算每日的获利盘比例,并观察其与价格走势的关系:

def analyze_profit_ratio(chip_distributions, close_prices):
    """
    分析每日获利盘比例
    
    参数:
    chip_distributions -- 每日筹码分布字典
    close_prices -- 收盘价Series
    
    返回:
    包含每日获利盘比例的Series
    """
    profit_ratios = []
    
    for date, dist in chip_distributions.items():
        close_price = close_prices[date]
        profit_ratio = calculate_profit_ratio(dist, close_price)
        profit_ratios.append(profit_ratio)
    
    return pd.Series(profit_ratios, index=close_prices.index)

3.2 筹码分布热力图

为了直观展示筹码分布随时间的变化,我们可以创建热力图:

def plot_chip_heatmap(chip_distributions, price_bins=20):
    """
    绘制筹码分布热力图
    
    参数:
    chip_distributions -- 每日筹码分布字典
    price_bins -- 价格区间数量
    """
    # 准备数据
    all_dates = sorted(chip_distributions.keys())
    all_prices = [price for dist in chip_distributions.values() for price in dist.keys()]
    
    # 确定价格区间
    min_price = min(all_prices)
    max_price = max(all_prices)
    bin_edges = np.linspace(min_price, max_price, price_bins+1)
    
    # 初始化热力图数据
    heatmap_data = np.zeros((len(all_dates), price_bins))
    
    for i, date in enumerate(all_dates):
        dist = chip_distributions[date]
        for price, amount in dist.items():
            # 确定价格所属的区间
            bin_idx = np.digitize(price, bin_edges) - 1
            bin_idx = max(0, min(bin_idx, price_bins-1))
            heatmap_data[i, bin_idx] += amount
    
    # 绘制热力图
    plt.figure(figsize=(12, 8))
    plt.imshow(heatmap_data.T, aspect='auto', cmap='hot', 
              extent=[0, len(all_dates), min_price, max_price],
              origin='lower')
    plt.colorbar(label='筹码密度')
    plt.xlabel('交易日')
    plt.ylabel('价格区间')
    plt.title('筹码分布热力图')
    
    # 调整x轴刻度
    tick_step = max(1, len(all_dates) // 10)
    plt.xticks(np.arange(0, len(all_dates), tick_step), 
              [all_dates[i].strftime('%Y-%m-%d') for i in range(0, len(all_dates), tick_step)],
              rotation=45)
    
    plt.tight_layout()
    plt.show()

4. 多指标融合与交易策略

单纯的筹码分析可能不够全面,我们需要将其与其他技术指标结合使用。

4.1 筹码与成交量结合分析

成交量是验证筹码分布变化的重要指标:

def analyze_volume_with_chips(data, chip_distributions):
    """
    分析成交量与筹码变化的关系
    
    参数:
    data -- 原始数据DataFrame
    chip_distributions -- 每日筹码分布字典
    
    返回:
    包含分析结果的DataFrame
    """
    result = pd.DataFrame(index=data.index)
    result['volume'] = data['volume']
    result['price'] = data['avg_price']
    
    # 计算每日筹码变化量
    chip_changes = []
    prev_dist = None
    for date, dist in chip_distributions.items():
        if prev_dist is None:
            chip_changes.append(0)
        else:
            # 计算筹码变化总量
            change = sum(abs(dist.get(p,0) - prev_dist.get(p,0)) for p in set(dist)|set(prev_dist))
            chip_changes.append(change)
        prev_dist = dist
    
    result['chip_change'] = chip_changes
    
    # 计算筹码变化与成交量的比率
    result['chip_volume_ratio'] = result['chip_change'] / result['volume']
    
    return result

4.2 构建综合交易信号

结合筹码分析、均线和成交量,我们可以构建更可靠的交易信号:

def generate_trading_signals(data, chip_distributions, 
                           short_window=5, long_window=20):
    """
    生成综合交易信号
    
    参数:
    data -- 原始数据DataFrame
    chip_distributions -- 每日筹码分布字典
    short_window -- 短期均线窗口
    long_window -- 长期均线窗口
    
    返回:
    包含交易信号的DataFrame
    """
    signals = pd.DataFrame(index=data.index)
    signals['price'] = data['avg_price']
    
    # 计算均线
    signals['short_ma'] = signals['price'].rolling(window=short_window).mean()
    signals['long_ma'] = signals['price'].rolling(window=long_window).mean()
    
    # 计算获利盘比例
    profit_ratios = analyze_profit_ratio(chip_distributions, signals['price'])
    signals['profit_ratio'] = profit_ratios
    
    # 计算筹码稳定性指标
    chip_stability = []
    prev_dist = None
    for date, dist in chip_distributions.items():
        if prev_dist is None:
            chip_stability.append(0)
        else:
            # 计算筹码分布的变化程度
            change = sum(abs(dist.get(p,0) - prev_dist.get(p,0)) for p in set(dist)|set(prev_dist))
            chip_stability.append(1 - change)
        prev_dist = dist
    
    signals['chip_stability'] = chip_stability
    
    # 生成交易信号
    signals['signal'] = 0
    
    # 条件1: 短期均线上穿长期均线
    signals.loc[signals['short_ma'] > signals['long_ma'], 'signal'] += 1
    
    # 条件2: 获利盘比例在合理区间(30%-70%)
    signals.loc[(signals['profit_ratio'] > 0.3) & 
               (signals['profit_ratio'] < 0.7), 'signal'] += 1
    
    # 条件3: 筹码稳定性高于阈值
    signals.loc[signals['chip_stability'] > 0.7, 'signal'] += 1
    
    # 综合信号: 当满足至少2个条件时产生交易信号
    signals['final_signal'] = signals['signal'] >= 2
    
    return signals

提示:实际应用中,应该在不同的市场环境下测试和优化这些参数和条件,以找到最适合特定股票或市场的设置。

更多推荐