写在前面
上一次的筹码分布的版本,有人反应是tushare的接口无法直接访问,而且涉及到一些复杂的复权因子的方法,好多人说看不懂上一次的链接,
筹码分布方法
接下来这个使用的是免费的akshare的,而且我通过一些特殊的方法拿到了一些证券公司计算这个指标的正经的方法来实现了这个接口,老规矩,我也不太喜欢说太多话,talk is cheap show me the code
还是不会用的,或者有想做量化的好兄弟可以一起交流一下,财务和技术,在下都略懂一些拳脚,一起合作肯定比单打独斗的强~~~
原理
通过当天的价格和量的指标,分别维持一个价格的区间的比例,通过一定的换手率的数据进行筹码衰减和交换 ,得到最后的成本,集中度,筹码获利比例的方法。
收费
这篇文章,我也不想收费了,还要送大家14元。这里我想给大家推荐一个网站,如果你的deep seek的r1模型一直不能及时响应,你可以使用一下硅基流动的网页,从这里注册,可以免费获取14元的流量的额度,2000万的token流量,够你问几万个问题了~~~独立的页面单独服务,不会提示网络繁忙。
而且,后期如果你要搭建自己的大模型的问答系统,硅基流动可以直接生成API,选择多种模型来搭建本地的LLM大模型,或者文生图,语音转换等等。从这里注册哦
core 代码
class ChipDistributionAnalyzer:
"""筹码分布分析器"""
def __init__(self, kdata: pd.DataFrame, accuracy_factor: int = 150, calc_range: Optional[int] = None):
"""
初始化筹码分布分析器
Args:
kdata: K线数据,必须包含 [开盘, 收盘, 最高, 最低, 成交量, 换手率] 等字段
accuracy_factor: 精度因子,决定价格分割的精度
calc_range: 计算的K线范围,默认使用全部数据
"""
self._validate_data(kdata)
self.kdata = kdata
self.factor = accuracy_factor
self.range = calc_range
# 设置matplotlib中文显示
plt.rcParams['font.family'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
def _validate_data(self, kdata: pd.DataFrame) -> None:
"""
验证输入数据的完整性
Args:
kdata: 待验证的K线数据
Raises:
ValueError: 当数据不完整或格式不正确时抛出
"""
required_columns = ['开盘', '收盘', '最高', '最低', '成交量', '换手率']
missing_columns = [col for col in required_columns if col not in kdata.columns]
if missing_columns:
raise ValueError(f"K线数据缺少必要字段: {missing_columns}")
def calculate_chip_distribution(self, index: int) -> Dict:
"""
计算指定位置的筹码分布
Args:
index: K线位置索引
Returns:
包含筹码分布结果的字典
"""
# 确定计算范围
start = max(0, index - self.range + 1) if self.range else 0
kdata = self.kdata.iloc[start:index + 1]
# 确定价格范围
max_price = max(kdata['最高'].values)
min_price = min(kdata['最低'].values)
# 计算精度
accuracy = max(0.01, (max_price - min_price) / (self.factor - 1))
# 初始化分布数组
price_range = [round(min_price + accuracy * i, 2) for i in range(self.factor)]
distribution = [0] * self.factor
# 计算每个K线的贡献
for _, row in kdata.iterrows():
distribution = self._calculate_k_line_contribution(
row, distribution, min_price, accuracy, price_range
)
return self._calculate_distribution_metrics(
distribution, price_range, self.kdata['收盘'].iloc[index]
)
def _calculate_k_line_contribution(
self,
kline: pd.Series,
distribution: List[float],
min_price: float,
accuracy: float,
price_range: List[float]
) -> List[float]:
"""
计算单个K线对筹码分布的贡献
Args:
kline: 单个K线数据
distribution: 现有筹码分布
min_price: 最小价格
accuracy: 价格精度
price_range: 价格范围数组
Returns:
更新后的筹码分布
"""
open_price = kline['开盘']
close_price = kline['收盘']
high_price = kline['最高']
low_price = kline['最低']
turnover_rate = min(1, kline['换手率'] / 100)
# 计算平均价格
avg_price = (open_price + close_price + high_price + low_price) / 4
# 计算价格区间索引
low_idx = max(0, int((low_price - min_price) / accuracy))
high_idx = min(self.factor - 1, int((high_price - min_price) / accuracy))
# 衰减现有筹码
distribution = [d * (1 - turnover_rate) for d in distribution]
# 一字板特殊处理
if high_price == low_price:
idx = int((high_price - min_price) / accuracy)
distribution[idx] += turnover_rate / 2
else:
# 计算三角形分布
for idx in range(low_idx, high_idx + 1):
price = price_range[idx]
if price <= avg_price:
weight = (price - low_price) / (avg_price - low_price)
else:
weight = (high_price - price) / (high_price - avg_price)
distribution[idx] += weight * turnover_rate
return distribution
def _calculate_distribution_metrics(
self,
distribution: List[float],
price_range: List[float],
current_price: float
) -> Dict:
"""
计算筹码分布的各项指标
Args:
distribution: 筹码分布数组
price_range: 价格范围数组
current_price: 当前价格
Returns:
包含各项指标的字典
"""
total_weight = sum(distribution)
if total_weight == 0:
return {
'profit_ratio': 0,
'avg_cost': 0,
'cost_90_range': (0, 0),
'concentration_90': 0,
'cost_70_range': (0, 0),
'concentration_70': 0,
'prices': price_range,
'distribution': distribution,
'current_price': current_price
}
# 计算平均成本
avg_cost = sum(p * d for p, d in zip(price_range, distribution)) / total_weight
# 计算获利比例
profit_ratio = sum(d for p, d in zip(price_range, distribution) if p <= current_price) / total_weight
# 计算成本区间
cost_90_range, concentration_90 = self._calculate_cost_range(
price_range, distribution, total_weight, 0.9
)
cost_70_range, concentration_70 = self._calculate_cost_range(
price_range, distribution, total_weight, 0.7
)
return {
'prices': price_range,
'distribution': distribution,
'current_price': current_price,
'profit_ratio': profit_ratio,
'avg_cost': avg_cost,
'cost_90_range': cost_90_range,
'concentration_90': concentration_90,
'cost_70_range': cost_70_range,
'concentration_70': concentration_70
}
def _calculate_cost_range(
self,
price_range: List[float],
distribution: List[float],
total_weight: float,
threshold: float
) -> Tuple[Tuple[float, float], float]:
"""
计算指定比例的成本区间
Args:
price_range: 价格范围数组
distribution: 筹码分布数组
total_weight: 总权重
threshold: 阈值(如0.9表示90%)
Returns:
(成本区间元组, 集中度)
"""
sorted_prices = sorted(
[(p, d) for p, d in zip(price_range, distribution)],
key=lambda x: x[1],
reverse=True
)
cumsum = 0
cost_low = float('inf')
cost_high = float('-inf')
for price, dist in sorted_prices:
cumsum += dist
cost_low = min(cost_low, price)
cost_high = max(cost_high, price)
if cumsum >= threshold * total_weight:
break
concentration = (
(cost_high - cost_low) / (cost_high + cost_low) * 100
if cost_high + cost_low > 0 else 0
)
return (cost_low, cost_high), concentration
def visualize_distribution(self, chip_distribution: Dict, title_prefix: str = "") -> None:
"""
可视化筹码分布
Args:
chip_distribution: 筹码分布数据
title_prefix: 标题前缀
"""
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制筹码分布
for i in range(len(chip_distribution['prices'])):
color = 'red' if chip_distribution['prices'][i] < chip_distribution['current_price'] else 'green'
ax.barh(
chip_distribution['prices'][i],
chip_distribution['distribution'][i],
color=color,
alpha=0.6,
edgecolor='none'
)
# 设置标题和标签
title = f"筹码分布图: {title_prefix}\n"
title += f"当前股价: {chip_distribution['current_price']:.2f} "
title += f"获利比例: {chip_distribution['profit_ratio']*100:.2f}%"
ax.set_title(title, fontsize=12)
ax.set_xlabel('筹码占比', fontsize=10)
ax.set_ylabel('价格', fontsize=10)
# 添加指标说明
text_content = (
f"获利比例: {chip_distribution['profit_ratio']*100:.2f}%\n"
f"平均成本: {chip_distribution['avg_cost']:.2f}\n"
f"90%成本: {chip_distribution['cost_90_range'][0]:.2f}-{chip_distribution['cost_90_range'][1]:.2f}\n"
f"集中度: {chip_distribution['concentration_90']:.2f}%\n"
f"70%成本: {chip_distribution['cost_70_range'][0]:.2f}-{chip_distribution['cost_70_range'][1]:.2f}\n"
f"集中度: {chip_distribution['concentration_70']:.2f}%"
)
plt.text(
1.02, 0.5,
text_content,
transform=ax.transAxes,
verticalalignment='center',
bbox=dict(boxstyle='round', facecolor='white', alpha=0.8)
)
ax.grid(True, linestyle='--', alpha=0.3)
plt.show()
def calculate_all_distributions(self) -> List[Dict]:
"""
计算所有K线的筹码分布指标
Returns:
所有K线的筹码分布指标列表,每个元素包含:
- profit_ratio: 获利比例
- avg_cost: 平均成本
- concentration_70: 70%筹码集中度
- concentration_90: 90%筹码集中度
"""
results = []
min_price = min(self.kdata['最低'])
max_price = max(self.kdata['最高'])
price_step = (max_price - min_price) / (self.factor - 1)
# 预先计算价格区间
price_ranges = [round(min_price + price_step * i, 2) for i in range(self.factor)]
# 初始化筹码分布
distribution = [0] * self.factor
for i in range(len(self.kdata)):
k_line = self.kdata.iloc[i]
current_price = k_line['收盘']
# 更新当前K线的筹码分布
distribution = self._calculate_k_line_contribution(
k_line,
distribution,
min_price,
price_step,
price_ranges
)
# 计算关键指标
metrics = self._calculate_key_metrics(distribution, price_ranges, current_price)
results.append(metrics)
return results
def _calculate_key_metrics(self, distribution: List[float], price_ranges: List[float],
current_price: float) -> Dict:
"""
计算关键筹码分布指标
Args:
distribution: 筹码分布列表
price_ranges: 价格区间列表
current_price: 当前价格
Returns:
包含关键指标的字典
"""
total_chips = sum(distribution)
if total_chips == 0:
return {
'profit_ratio': 0,
'avg_cost': current_price,
'concentration_70': 0
}
# 1. 计算获利比例
profit_chips = sum(d for i, d in enumerate(distribution)
if price_ranges[i] <= current_price)
profit_ratio = profit_chips / total_chips
# 2. 计算平均成本
avg_cost = sum(price * dist for price, dist in zip(price_ranges, distribution)) / total_chips
# 3. 计算70%筹码集中度
target_chips = total_chips * 0.7
accumulated_chips = 0
price_range_count = 0
#
sorted_dist = sorted(zip(price_ranges, distribution),
key=lambda x: x[1], reverse=True)
for _, chips in sorted_dist:
accumulated_chips += chips
price_range_count += 1
if accumulated_chips >= target_chips:
break
concentration_70 = price_range_count / self.factor
# 4. 计算90%筹码集中度
target_chips = total_chips * 0.9
accumulated_chips = 0
price_range_count = 0
for _, chips in sorted_dist:
accumulated_chips += chips
price_range_count += 1
if accumulated_chips >= target_chips:
break
concentration_90 = price_range_count / self.factor
return {
'profit_ratio': profit_ratio,
'avg_cost': avg_cost,
'concentration_70': concentration_70,
'concentration_90': concentration_90
}
,这个里面直接使用了akshare的接口,理论上拿到可以直接拿到复权后的价格指标,然后iu就可以根据K线指标来计算了,当然你可以做更复杂的计算