import gzip
import numpy as np, pandas as pd
C = '/Users/xpresso/zt_app/code'

# --- 三列修复清单 ---
m = pd.read_csv(f'{C}/_repair_manifest_20260913_1434.csv.gz',
                dtype={'code': str, 'trade_date': str, 'field': str})
m['old'] = pd.to_numeric(m['old'], errors='coerce'); m['new'] = pd.to_numeric(m['new'], errors='coerce')
m['absd'] = (m['new'] - m['old']).abs()
m['reld'] = (m['new'] - m['old']).abs() / m['old'].abs().replace(0, np.nan)
print('=== 三列修复清单 (pre_close / change / pct_chg) ===')
print(m.groupby('field').agg(行数=('code', 'size'), 股票数=('code', 'nunique'),
                            中位绝对差=('absd', 'median'), p90绝对差=('absd', lambda s: s.quantile(.9)),
                            最大绝对差=('absd', 'max'), 中位相对差=('reld', 'median')).to_string())
# pct_chg 板幅阈值穿越(=可能翻转 T0 涨停判定)
LUP = {'main': 9.9, 'gem': 19.9, 'star': 19.9, 'bj': 29.9}
def board(code):
    c = code.split('.')[0]
    if c.startswith('688'): return 'star'
    if c.startswith('300') or c.startswith('301'): return 'gem'
    if c.startswith(('43', '83', '87', '92')): return 'bj'
    return 'main'
p = m[m['field'] == 'pct_chg'].copy()
p['bt'] = p['code'].map(lambda c: LUP[board(c)])
p['旧涨停'] = p['old'] >= p['bt']; p['新涨停'] = p['new'] >= p['bt']
p['穿越'] = p['旧涨停'] != p['新涨停']
print(f"\npct_chg: 共 {len(p)} 行; 阈值穿越(涨停判定翻转) {int(p['穿越'].sum())} 行 "
      f"(翻为涨停 {int((~p['旧涨停'] & p['新涨停']).sum())} / 翻离涨停 {int((p['旧涨停'] & ~p['新涨停']).sum())})")
print('  pct_chg 绝对值分布: 中位 %.3f p90 %.3f 最大 %.3f' % (p['absd'].median(), p['absd'].quantile(.9), p['absd'].max()))
# --- 因子清单 ---
a1 = pd.read_csv(f'{C}/_adjfactor_manifest_20260913_1505.csv.gz', dtype={'code': str, 'trade_date': str})
a2 = pd.read_csv(f'{C}/_adjfactor_manifest_20260913_1514.csv.gz', dtype={'code': str, 'trade_date': str})
for nm, a in [('因子轮1(逐日对齐tushare)', a1), ('因子轮2(tol=0 收尾)', a2)]:
    a['old'] = pd.to_numeric(a['old'], errors='coerce'); a['new'] = pd.to_numeric(a['new'], errors='coerce')
    d = (a['new'] - a['old']).abs(); r = d / a['old'].abs().replace(0, np.nan)
    print(f'\n=== {nm} ===')
    print(f'  行数 {len(a)} / 股票 {a["code"].nunique()} | 绝对差 中位 {d.median():.3e} p90 {d.quantile(.9):.3e} 最大 {d.max():.6f}'
          f' | 相对差 中位 {r.median():.3e} 最大 {r.max():.3e}')
    ex = a.loc[r.idxmax()]
    print(f'  最大相对差样例: {ex["code"]} {ex["trade_date"]} {ex["old"]} -> {ex["new"]} (rel {r.max():.3e})')
    smp = a.head(3)
    for _, s in smp.iterrows():
        print(f'    例: {s["code"]} {s["trade_date"]} 修前 {s["old"]} → 修后 {s["new"]}')
# 真除权日占比(因子相对自身前日变化)
a = pd.concat([a1, a2], ignore_index=True).drop_duplicates(['code', 'trade_date'], keep='last')
a['old'] = pd.to_numeric(a['old'], errors='coerce'); a['new'] = pd.to_numeric(a['new'], errors='coerce')
changed = (a['new'] != a['old']).mean()
print(f'\n因子合计去重行 {len(a)}, 修前≠修后占比 {changed*100:.1f}%')
