#!/usr/bin/env python3
"""模拟盘历史回放重算(2026-09-13 用户批准)

用途: 数据口径修正(pre_close/change/pct_chg/adj_factor)后, 按**当前定稿规则**(MAX_POS/MIN_STRENGTH)
      重放 0901 起的全部交易日, 重建 sim_trading_state.json / sim_trading_nav.csv。
      信号源 = backtest_zt_full/strength_baseline.csv 中 buy_date==当日 的行(scan_daily_tb.py 每日追加)。

安全: ① 先把现存 state/nav 备份到 _sim_replay_backup_<ts>/ ; ② --dry 只写 /tmp 沙箱, 不碰实盘;
      ③ 每日一行进度, 结束时打印逐日净值对照(回放 vs 备份的旧记录)。

用法: python code/replay_sim_live.py [--dry] [--from 20260901] [--to 20260911]
"""
import sys, os, json, csv, shutil, datetime

sys.path.insert(0, '/Users/xpresso/zt_app/code')
QUANT = '/Users/xpresso/zt_app'
STATE = f'{QUANT}/sim_trading_state.json'
NAV = f'{QUANT}/sim_trading_nav.csv'

argv = sys.argv[1:]
DRY = '--dry' in argv
def _arg(name, default=None):
    return argv[argv.index(name) + 1] if name in argv else default

import sim_live_daily as S   # 导入即加载 dailies/model(与实盘同口径)

# 交易日历: 四池并集
dates_all = sorted({d for pool in S.COMBO for code, df in S.cache[pool].items()
                    for d in df['trade_date'].values})
d_from = _arg('--from', '20260901')
d_to = _arg('--to', dates_all[-1])
DATES = [d for d in dates_all if d_from <= d <= d_to]
print(f"回放区间 {d_from}~{d_to} → {len(DATES)} 个交易日: {DATES[0]}..{DATES[-1]}")

if DRY:
    OUT = '/tmp/sim_replay_dry'
    BK = None
    os.makedirs(OUT, exist_ok=True)
    S.STATE_FILE, S.NAV_CSV = f'{OUT}/state.json', f'{OUT}/nav.csv'
    for f in (S.STATE_FILE, S.NAV_CSV):
        if os.path.exists(f):
            os.remove(f)
    print(f"[DRY] 沙箱输出 {OUT}, 不动实盘")
else:
    ts = datetime.datetime.now().strftime('%Y%m%d_%H%M')
    BK = f'{QUANT}/_sim_replay_backup_{ts}'
    os.makedirs(BK, exist_ok=True)
    for f in (STATE, NAV):
        if os.path.exists(f):
            shutil.copy2(f, BK)
    with open(f'{BK}/README.txt', 'w') as fh:
        fh.write(f"回放前备份(重算前的历史记录)\n时间 {ts}\n区间 {d_from}~{d_to}\n"
                 f"回放脚本 code/replay_sim_live.py; 还原: cp {BK}/*.json|*.csv 回 {QUANT}/\n")
    print(f"[实跑] 旧记录已备份 → {BK}")
    # 重算必须从空状态起跑(否则 main() 见 last_date 已到最新日会整段跳过 → 变成空操作)
    for f in (STATE, NAV):
        if os.path.exists(f):
            os.remove(f)
    print("[实跑] 实盘 state/nav 已清空(备份在上一行目录), 按区间重放")
    S.STATE_FILE, S.NAV_CSV = STATE, NAV

for d in DATES:
    S.main(today=d)

st = json.load(open(S.STATE_FILE))
new_nav = list(csv.reader(open(S.NAV_CSV)))[1:]
print('\n===== 回放结果 =====')
print(f"期末总资产 {float(new_nav[-1][4]):,.2f} ({(float(new_nav[-1][4])/100000-1)*100:+.2f}%) | "
      f"现金 {st['cash']:,.2f} | 持仓 {len(st['positions'])} 只 | 已平仓 {len(st['closed'])} 笔")
if st['closed']:
    w = sum(1 for c in st['closed'] if c['pnl'] > 0)
    print(f"平仓胜率 {w/len(st['closed'])*100:.0f}% | 合计净收益 "
          f"{sum(c['ret_net'] for c in st['closed'])*100:+.1f}%")
old_nav = []
if not DRY and os.path.exists(f'{BK}/sim_trading_nav.csv'):
    old_nav = list(csv.reader(open(f'{BK}/sim_trading_nav.csv')))[1:]
if old_nav:
    print('\n日期        回放total      旧记录total')
    om = {r[0]: r for r in old_nav}
    for r in new_nav:
        o = om.get(r[0])
        print(f"{r[0]}  {float(r[4]):>12,.2f}  {float(o[4]):>12,.2f}" if o else f"{r[0]}  {float(r[4]):>12,.2f}  -")