#!/usr/bin/env python3
"""qfq 偏差来源归因: 偏差>1e-5 的文件 vs 66 只 raw 回填名单 / 末行因子变化"""
import os, glob
import pandas as pd, numpy as np
BASE = os.path.expanduser('~/zt_app/backtest_zt_full')
BAK = os.path.expanduser('~/zt_app/_hfq_ohlc_backup_20260912')
back66 = {os.path.basename(f).split('__')[-1][:-4] for f in glob.glob(os.path.expanduser('~/zt_app/_raw_backfill_backup_20260912/*.csv'))}
cur = {os.path.basename(f)[:-4]: f for p in ['hs300','zz500','zz1000','zz2000'] for f in glob.glob(f'{BASE}/daily_{p}/*.csv')}
big = set()
for bf in sorted(glob.glob(f'{BAK}/*.csv')):
    code = os.path.basename(bf)[:-4]
    if code not in cur: continue
    d = pd.read_csv(bf, dtype={'trade_date': str})
    if 'qfq_close' not in d.columns: continue
    c = pd.read_csv(cur[code], dtype={'trade_date': str})
    m = d.merge(c, on='trade_date', suffixes=('_o','_c'))
    if not len(m): continue
    fac = m['adj_factor'].astype(float); rc = m['raw_close_c'].astype(float)
    der = (rc*fac/fac.iloc[-1]).round(4); old = m['qfq_close'].astype(float)
    rel = (old-der).abs()/old.abs().clip(lower=1e-9)
    if (rel > 1e-5).any():
        big.add(code)
print('偏差>1e-5 文件数:', len(big))
print('其中属于 66 只 raw 回填名单:', len(big & back66), sorted(big & back66)[:12])
print('不在回填名单:', len(big - back66), sorted(big - back66)[:12])
# 末行因子比对: 用旧文件末行隐含因子 vs 现因子
mism = 0; samples = []
for code in sorted(big - back66)[:200]:
    bf, cf = f'{BAK}/{code}.csv', cur[code]
    d = pd.read_csv(bf, dtype={'trade_date': str}); c = pd.read_csv(cf, dtype={'trade_date': str})
    if 'hfq_close' not in d.columns: continue
    old_lt = float(d['hfq_close'].iloc[-1])/float(d['raw_close'].iloc[-1])
    new_lt = float(c['adj_factor'].iloc[-1])
    if abs(old_lt-new_lt)/new_lt > 1e-9:
        mism += 1
        if len(samples) < 6: samples.append((code, round(old_lt,4), round(new_lt,4), round((old_lt/new_lt-1)*100, 4)))
print(f'非回填名单中 末行归一因子不一致: {mism} / {len(big-back66)}')
print(' 例:', samples)
