import pandas as pd
import numpy as np
import talib
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
def calculate_winner(close, window=250):
winner = np.zeros(len(close))
for i in range(len(close)):
if i < window:
winner[i] = np.nan
continue
current_price = close[i]
window_prices = close[i - window:i]
# 计算在窗口内低于当前价格的比例
winner[i] = np.sum(window_prices <= current_price) / len(window_prices)
return winner
def calculate_zshjj_zzljj(df):
"""计算紫气东来/寻龙起爆主力控盘和散户套牢指标"""
# 计算获利盘比例
df['winner_close'] = calculate_winner(df['close'])
# 计算10%区间内的筹码
df['winner_high'] = calculate_winner(df['close'] * 1.1)
df['winner_low'] = calculate_winner(df['close'] * 0.9)
df['winner_band'] = df['winner_high'] - df['winner_low']
# 计算主力筹码和散户筹码
df['ZLCM'] = talib.EMA(df['winner_close'] * 70, timeperiod=3)
df['SHCM'] = talib.EMA(df['winner_band'] * 80, timeperiod=3)
# 计算筹码系数
df['ZSHTL'] = df['SHCM'] / (df['ZLCM'] + df['SHCM']) * 100
df['ZZLKP'] = df['ZLCM'] / (df['ZLCM'] + df['SHCM']) * 100
# 计算55日警戒线
df['ZSHJJ'] = talib.EMA(df['ZSHTL'], timeperiod=55)
df['ZZLJJ'] = talib.EMA(df['ZZLKP'], timeperiod=55)
# 机构持仓比例
df[
'institutional_holding'] = df['ZZLKP']
# 散户持仓比例
df['retail_holding'] = df['ZSHTL'].astype(int)
return df
def plot_chip_indicators(df):
"""绘制紫气东来/寻龙起爆筹码分布指标图"""
fig, ax = plt.subplots(figsize=(14, 7))
# 设置x轴为日期
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
plt.xticks(rotation=45)
# 1. 绘制散户套牢筹码(灰色区域)
ax.bar(df.index, df['ZSHTL'], color='gray', width=1, label='Retail Holding')
# 2. 绘制主力控盘筹码(蓝色)
mask_blue = df['ZZLKP'] > 20
ax.bar(df.index, df['ZZLKP'], width=1, color='blue', alpha=0.6, label='Main Control')
# 3. 绘制主力警戒线(黄色)
ax.plot(df.index, df['ZZLJJ'], color='yellow', linewidth=2, label='Main Alert')
# 4. 绘制散户警戒线(浅灰色)
ax.plot(df.index, df['ZSHJJ'], color='lightgray', linestyle='--', label='Retail Alert')
mask_top = df['ZZLKP'] > 95
ax.bar(df.index[mask_top], df['ZZLKP'][mask_top], width=1, color='green', alpha=0.5, label='Top Risk')
mask_pit = df['ZZLKP'] <= 10
ax.bar(df.index[mask_pit], df['ZZLKP'][mask_pit], width=1, color='purple', alpha=0.7, label='Bottom Pit')
# 设置图例和标题
ax.set_title('Main Control and Retail Chips Distribution')
ax.set_ylabel('Percentage (%)')
ax.legend(loc='upper left')
plt.tight_layout()
plt.show()
if __name__ == "__main__":
dates = pd.date_range(start='2023-01-01', periods=300, freq='D')
np.random.seed(42)
prices = np.cumprod(1 + np.random.randn(300) * 0.01) * 100
df = pd.DataFrame({
'date'
: dates,
'close': prices
}).set_index('date')
# 计算指标
df = calculate_zshjj_zzljj(df)
# 显示最后几行数据
print("机构持仓比例:", df['institutional_holding'].iloc[-1])
print("散户持仓比例:", df['retail_holding'].iloc[-1])
# 绘制图表
plot_chip_indicators(df[-100:]) # 仅显示最后100个数据点