import akshare as ak
import pandas as pd
import numpy as np
import os
import ast
import time
import mplfinance as mpf
import matplotlib.pyplot as plt

# from flask import Flask, render_template, jsonify

# # 读取数据（注意替换实际文件路径）
file_path = r"C:\Users\zhouj\Desktop\IM888_5MIN_2024_ofdata.csv"
df = pd.read_csv(file_path, parse_dates=["datetime"], index_col="datetime").sort_index()

# 使用akshare获取数据 
symbol_name = 'IM2503'
time_period = 30
# df = ak.futures_zh_minute_sina(symbol=symbol_name, period="15")

# ultimate_smoother函数
def ultimate_smoother(price, period):
    # 初始化变量（修正角度单位为弧度）
    a1 = np.exp(-1.414 * np.pi / period)
    b1 = 2 * a1 * np.cos(1.414 * np.pi / period)  # 将180改为np.pi
    c2 = b1
    c3 = -a1**2
    c1 = (1 + c2 - c3) / 4

    # 准备输出序列
    us = np.zeros(len(price))
    us_new = np.zeros(len(price))
    trend = [None] * (len(price))
    ma_close = np.zeros(len(price))

    # 前4个点用原始价格初始化
    for i in range(len(price)):
        if i < 4:
            us[i] = price[i]
        else:
            # 应用递归公式
            us[i] = (1 - c1) * price[i] + (2 * c1 - c2) * price[i-1] \
                    - (c1 + c3) * price[i-2] + c2 * us[i-1] + c3 * us[i-2]

        us_new = np.around(us, decimals=2)
        ma_close = price.rolling(window=5 * period).mean()

        if us_new[i] > price[i] and ma_close[i] > price[i]:
            trend[i] = '空头趋势'
        elif us_new[i] < price[i] and ma_close[i] < price[i]:
            trend[i] = '多头趋势'
        else:
            trend[i] = '无趋势'

    return us_new, trend

def safe_literal_eval(x):
    """带异常处理的安全转换"""
    try:
        return ast.literal_eval(x)
    except:
        return []  # 返回空列表作为占位符

def add_poc_column(df):
    # 安全转换列数据
    df['price'] = df['price'].apply(safe_literal_eval)
    df['Ask'] = df['Ask'].apply(lambda x: list(map(int, safe_literal_eval(x))))
    df['Bid'] = df['Bid'].apply(lambda x: list(map(int, safe_literal_eval(x))))
    
    # 定义处理函数（带数据验证）
    def find_poc(row):
        # 验证三个列表长度一致且非空
        if not (len(row['price']) == len(row['Ask']) == len(row['Bid']) > 0):
            return '缺值'  # 返回空值标记异常数据
        
        sums = [a + b for a, b in zip(row['Ask'], row['Bid'])]
        try:
            max_index = sums.index(max(sums))
            return row['price'][max_index]
        except ValueError:
            return '缺值'  # 处理空求和列表情况
    
    # 应用处理函数
    df['POC'] = df.apply(find_poc, axis=1)
    
    # 可选：统计异常数据
    error_count = df['POC'].isnull().sum()
    if error_count > 0:
        print(f"警告：发现 {error_count} 行异常数据（已标记为NaN）")
    
    return df['POC']
df.reset_index()
# df['datetime'] = pd.to_datetime(df['datetime'])
df['终极平滑值'], df['趋势方向'] = ultimate_smoother(df["close"], time_period)
df['POC'] = add_poc_column(df)
df.index = pd.to_datetime(df.index)
print(df.head(5))

# 规范列名（兼容MA列）
df = df.rename(columns={"close": "Close", "open": "Open", "high": "High", "low": "Low", "volume":"Volume"})

# 创建一个新的DataFrame来存储有效的POC值
valid_poc = pd.DataFrame(index=df.index)  # 创建与主数据相同索引的DataFrame
valid_poc['POC'] = df['POC'].apply(lambda x: float(x) if x != '缺值' else np.nan)  # 将有效POC值转换为float，无效值设为NaN

# 创建附加绘图对象（关键步骤）
apd = [
    mpf.make_addplot(
        df["终极平滑值"],  # MA数据列
        color="dodgerblue",  # 线条颜色
        width=1,  # 线宽
        panel=0,  # 显示在主图区域
        ylabel="终极平滑值",  # 右侧Y轴标签
        mav=(60),#绘制均线
        secondary_y=True,  # 与主图共享左侧Y轴
    ),
    mpf.make_addplot(
        valid_poc['POC'],  # 使用处理后的POC值
        type='scatter',  # 使用散点图
        marker='o',  # 圆形标记
        markersize=100,  # 标记大小
        color='yellow',  # 标记颜色
        alpha=0.5,  # 透明度
        panel=0,  # 显示在主图区域
        ylabel="POC",  # 右侧Y轴标签
        secondary_y=False,  # 与主图共享左侧Y轴
    )
]

# 定义 mplfinance 的自定义风格
mc = mpf.make_marketcolors(up='r', down='g', volume='inherit')
s = mpf.make_mpf_style(base_mpf_style='charles', marketcolors=mc, rc={'font.sans-serif': ['Microsoft YaHei']})

# 创建图形
fig, axes = mpf.plot(
    df,
    type="candle",
    style=s,
    addplot=apd,  # 添加ultimate_smoother线和POC散点
    title=f"{symbol_name} K-Line with ultimate_smoother and POC",
    ylabel="Price",
    show_nontrading=False,
    returnfig=True  # 返回图形对象
)

# 获取主图轴对象
ax = axes[0]

# 添加POC值标注
for idx, row in valid_poc.iterrows():
    if pd.notnull(row['POC']):
        ax.annotate(
            f'{row["POC"]:.2f}',
            xy=(idx, row['POC']),
            xytext=(10, 10),
            textcoords='offset points',
            color='black',
            fontsize=8,
            bbox=dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.5),
            arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0')
        )

# 显示图形
plt.show()

