"""
缠论完整引擎 v2.0
K线→包含处理→分型→笔→线段→中枢→走势类型→买卖点
"""
import pandas as pd, numpy as np

df_raw = pd.read_parquet("data/btc_multidim.parquet")
d = df_raw.resample("1h").agg({"open":"first","high":"max","low":"min","close":"last"}).dropna()
O, H, L, C = d["open"].values, d["high"].values, d["low"].values, d["close"].values
n = len(d)

# ════════════════════ 1. 包含处理 ════════════════════
def han_bao(O, H, L, C):
    """K线包含关系处理"""
    merged = [(O[0], H[0], L[0], C[0])]
    direction = 1  # 1上,-1下
    
    for i in range(1, n):
        po, ph, pl, pc = merged[-1]
        co, ch, cl, cc = O[i], H[i], L[i], C[i]
        
        # 判断包含
        is_bao = (cl >= pl and ch <= ph) or (cl <= pl and ch >= ph)
        
        if is_bao:
            if direction == 1:  # 上升取高高
                merged[-1] = (po, max(ph,ch), max(pl,cl), cc)
            else:  # 下降取低低
                merged[-1] = (po, min(ph,ch), min(pl,cl), cc)
        else:
            direction = 1 if ch > ph else -1
            merged.append((co, ch, cl, cc))
    
    arr = np.array(merged)
    return pd.DataFrame({"open":arr[:,0],"high":arr[:,1],"low":arr[:,2],"close":arr[:,3]})

df_m = han_bao(O, H, L, C)
Hm, Lm = df_m["high"].values, df_m["low"].values
nm = len(df_m)

print(f"包含处理: {n}→{nm} K线")

# ════════════════════ 2. 分型 ════════════════════
fx = []
for i in range(1, nm-1):
    if Hm[i] > Hm[i-1] and Hm[i] > Hm[i+1] and Lm[i] > Lm[i-1] and Lm[i] > Lm[i+1]:
        fx.append({"idx": i, "type": "顶", "price": Hm[i]})
    elif Lm[i] < Lm[i-1] and Lm[i] < Lm[i+1] and Hm[i] < Hm[i-1] and Hm[i] < Hm[i+1]:
        fx.append({"idx": i, "type": "底", "price": Lm[i]})

print(f"分型: {len(fx)}")

# ════════════════════ 3. 笔 ════════════════════
bi = []
i = 0
while i < len(fx) - 1:
    f1 = fx[i]
    best = None
    for j in range(i+1, len(fx)):
        f2 = fx[j]
        if f2["type"] == f1["type"]: continue
        if f2["idx"] - f1["idx"] < 3: continue  # 至少隔1根K线
        
        if f1["type"] == "底" and f2["price"] > f1["price"]:
            # 验证中间不跌破底
            mid_low = min(Lm[f1["idx"]:f2["idx"]+1])
            if mid_low >= f1["price"]:
                best = j; break
        elif f1["type"] == "顶" and f2["price"] < f1["price"]:
            mid_high = max(Hm[f1["idx"]:f2["idx"]+1])
            if mid_high <= f1["price"]:
                best = j; break
    
    if best is not None:
        f2 = fx[best]
        bi.append({
            "start": f1["idx"], "end": f2["idx"],
            "dir": "up" if f1["type"]=="底" else "down",
            "start_px": f1["price"], "end_px": f2["price"],
            "start_high": Hm[f1["idx"]], "start_low": Lm[f1["idx"]],
            "end_high": Hm[f2["idx"]], "end_low": Lm[f2["idx"]],
        })
        i = best
    else:
        i += 1

print(f"笔: {len(bi)}")

# ════════════════════ 4. 线段 ════════════════════
def find_xduan(bi):
    """线段: 至少3笔组成, 被反向笔破坏"""
    if len(bi) < 3: return []
    
    xd = []
    i = 0
    while i < len(bi) - 2:
        b1, b2, b3 = bi[i], bi[i+1], bi[i+2]
        
        # 方向交替检查
        if b1["dir"] == b2["dir"]:
            i += 1; continue
        if b2["dir"] != b3["dir"]:
            i += 1; continue
        
        # 线段被破坏: b3突破b1端点
        if b1["dir"] == "up" and b3["end_px"] > b1["end_px"]:
            # 上升线段确认
            seg_high = max(b["end_high"] for b in bi[i:i+3])
            seg_low = min(b["start_low"] for b in bi[i:i+3])
            xd.append({"start_bi": i, "end_bi": i+2, "dir": "up",
                       "high": seg_high, "low": seg_low})
            i += 3
        elif b1["dir"] == "down" and b3["end_px"] < b1["end_px"]:
            seg_high = max(b["start_high"] for b in bi[i:i+3])
            seg_low = min(b["end_low"] for b in bi[i:i+3])
            xd.append({"start_bi": i, "end_bi": i+2, "dir": "down",
                       "high": seg_high, "low": seg_low})
            i += 3
        else:
            i += 1
    
    return xd

xd = find_xduan(bi)
print(f"线段: {len(xd)}")

# ════════════════════ 5. 中枢 ════════════════════
def find_zhongshu(xd):
    """中枢: 连续3个线段的重叠区间"""
    zs_list = []
    i = 0
    
    while i < len(xd) - 2:
        highs = [x["high"] for x in xd[i:i+3]]
        lows = [x["low"] for x in xd[i:i+3]]
        
        ZG = min(highs)
        ZD = max(lows)
        
        if ZG > ZD:
            end = i + 3
            while end < len(xd):
                h, l = xd[end]["high"], xd[end]["low"]
                if max(ZG, h) - min(ZD, l) > 0 and h > ZD and l < ZG:
                    ZG = min(ZG, h)
                    ZD = max(ZD, l)
                    end += 1
                else:
                    break
            
            zs_list.append({"start_xd": i, "end_xd": end-1,
                           "ZG": ZG, "ZD": ZD, "ZZ": (ZG+ZD)/2})
            i = end
        else:
            i += 1
    
    return zs_list

zs = find_zhongshu(xd)
print(f"中枢: {len(zs)}")

# ════════════════════ 6. 走势类型 + 买卖点 ════════════════════
# 两个中枢以上=趋势, 一个=盘整
if len(zs) >= 2:
    zs_sorted = sorted(zs, key=lambda z: z["start_xd"])
    print(f"\n--- 走势类型分析 ---")
    
    for i in range(len(zs_sorted) - 1):
        z1, z2 = zs_sorted[i], zs_sorted[i+1]
        if z2["ZZ"] > z1["ZZ"]:
            print(f"  中枢{i}→{i+1}: 上升趋势 (ZZ {z1['ZZ']:.0f}→{z2['ZZ']:.0f})")
        else:
            print(f"  中枢{i}→{i+1}: 下降趋势")
    
    # 最后一个中枢的买卖点
    last_zs = zs_sorted[-1]
    ZG, ZD, ZZ = last_zs["ZG"], last_zs["ZD"], last_zs["ZZ"]
    print(f"\n  最后中枢: ZG={ZG:.0f} ZD={ZD:.0f} ZZ={ZZ:.0f}")
    
    # 中枢后的价格
    last_xd_end = xd[last_zs["end_xd"]]
    last_bi_end = bi[last_xd_end["end_bi"]]
    end_idx = last_bi_end["end"]
    
    # 当前价格相对中枢位置
    current_px = C[-1]
    if current_px > ZG:
        print(f"  当前价格 {current_px:.0f} > ZG({ZG:.0f}) — 中枢上方")
        print(f"  可能: 第三类买点(回踩ZG不破)")
    elif current_px < ZD:
        print(f"  当前价格 {current_px:.0f} < ZD({ZD:.0f}) — 中枢下方")
        print(f"  可能: 第一类买点(背驰) 或 第三类卖点")
    else:
        print(f"  当前价格在中枢内 — 盘整，等待方向")
    
    print(f"\n  中枢后价格: {df_m['close'].iloc[end_idx:].describe().round(0).to_string()}")

elif len(zs) == 1:
    print(f"\n  盘整: 单一中枢 ZG={zs[0]['ZG']:.0f} ZD={zs[0]['ZD']:.0f}")
else:
    print(f"\n  无中枢 — 数据周期太短或趋势太强")
