"""
uj_diagnostic.py
================
Answers Bennett's specific doubts about the USDJPY leg:

1. WHERE does UJ make its money? P&L broken down by exit reason
   (tp / stop / hold_expiry / zscore). If profit is TP-driven, structure works.
   If it leans on hold-expiry or a few outliers, the edge is shaky.

2. THE EXPIRY PROBLEM: what % of UJ trades actually hit TP within 24h vs time
   out at hold-expiry? Bennett suspects the 0.70% target is too far for a 24h
   window. We measure it exactly.

3. OUTLIER DEPENDENCE: how concentrated is UJ's profit? Top-10 trades' share of
   total P&L. If a handful of trades carry it, edge is fragile.

4. INTERVENTION SENSITIVITY: UJ P&L by year, flagging known BoJ intervention
   periods (2022 H2, 2024, 2026). If losses concentrate there, structural risk.

5. DOES UJ EARN ITS PLACE? Basic stats: win rate, profit factor, avg win/loss,
   expectancy per trade, total P&L. Compare to make an EU-only decision.

Reads usdjpy_trades_real_costs.csv. Columns (confirmed earlier):
  entry_time, exit_reason, entry_price, exit_price, direction, zscore,
  zscore_abs, mult, cost_pips, cost_usd, pnl_bt, pnl_real, mfe_pct, mae_pct,
  year, month
"""
import csv, sys
from pathlib import Path
from collections import defaultdict
from datetime import datetime

def resolve_base():
    for b in [Path(r"C:\Users\Administrator\OneDrive\fx_macro_intraday"),
              Path(r"C:\Users\paul_\OneDrive\fx_macro_intraday")]:
        if b.exists(): return b
    sys.exit("base not found")
BASE=resolve_base()

p = BASE/"data"/"processed"/"usdjpy_trades_real_costs.csv"
rows=[]
with open(p, newline="", encoding="utf-8-sig") as f:
    for r in csv.DictReader(f):
        try:
            r["pnl_real"]=float(r["pnl_real"])
            r["mae_pct"]=float(r.get("mae_pct",0) or 0)
            r["mfe_pct"]=float(r.get("mfe_pct",0) or 0)
            r["year"]=int(float(r.get("year",0) or 0))
            r["zscore_abs"]=float(r.get("zscore_abs",0) or 0)
        except (ValueError,KeyError):
            continue
        rows.append(r)

n=len(rows)
total=sum(r["pnl_real"] for r in rows)
wins=[r for r in rows if r["pnl_real"]>0]
losses=[r for r in rows if r["pnl_real"]<=0]
print("="*70)
print(f"USDJPY DIAGNOSTIC  ({n} trades, 2003-2026)")
print("="*70)

# ---- 5. headline stats ----
gross_win=sum(r["pnl_real"] for r in wins)
gross_loss=sum(r["pnl_real"] for r in losses)
pf = (gross_win/abs(gross_loss)) if gross_loss else float('inf')
print(f"\n[HEADLINE]")
print(f"  Total P&L         : ${total:,.0f}")
print(f"  Win rate          : {100*len(wins)/n:.1f}%  ({len(wins)}W / {len(losses)}L)")
print(f"  Avg win           : ${gross_win/len(wins):,.0f}" if wins else "  Avg win: n/a")
print(f"  Avg loss          : ${gross_loss/len(losses):,.0f}" if losses else "  Avg loss: n/a")
print(f"  Profit factor     : {pf:.2f}   (gross win / gross loss)")
print(f"  Expectancy/trade  : ${total/n:,.1f}")

# ---- 1. P&L by exit reason ----
print(f"\n[1. WHERE THE MONEY COMES FROM - P&L by exit reason]")
by_reason_pnl=defaultdict(float); by_reason_n=defaultdict(int); by_reason_w=defaultdict(int)
for r in rows:
    er=r.get("exit_reason","?")
    by_reason_pnl[er]+=r["pnl_real"]; by_reason_n[er]+=1
    if r["pnl_real"]>0: by_reason_w[er]+=1
print(f"  {'reason':<14}{'count':>7}{'totP&L':>12}{'avgP&L':>10}{'win%':>7}{'%ofProfit':>11}")
for er in sorted(by_reason_pnl, key=lambda k:-by_reason_pnl[k]):
    c=by_reason_n[er]; tp=by_reason_pnl[er]
    print(f"  {er:<14}{c:>7}{tp:>12,.0f}{tp/c:>10,.0f}"
          f"{100*by_reason_w[er]/c:>6.0f}%{100*tp/total:>10.0f}%")

# ---- 2. expiry problem ----
tp_n=by_reason_n.get("tp",0); exp_n=by_reason_n.get("hold_expiry",0); st_n=by_reason_n.get("stop",0)
print(f"\n[2. THE EXPIRY PROBLEM - does the 0.70% TP get hit in 24h?]")
print(f"  Hit TP            : {tp_n} ({100*tp_n/n:.0f}%)")
print(f"  Timed out (expiry): {exp_n} ({100*exp_n/n:.0f}%)")
print(f"  Stopped out       : {st_n} ({100*st_n/n:.0f}%)")
if exp_n>=tp_n:
    print(f"  >>> CONFIRMED: more trades TIME OUT than hit target. TP likely too far")
    print(f"      for the 24h window, OR hold too short. Worth testing tighter TP")
    print(f"      or longer hold.")
else:
    print(f"  >>> TP is hit more often than timeout - structure is working as intended.")
# how profitable are the expiry trades?
exp_pnl=by_reason_pnl.get("hold_expiry",0)
print(f"  Hold-expiry trades net: ${exp_pnl:,.0f} "
      f"({'profitable on balance' if exp_pnl>0 else 'net losing'})")

# ---- 3. outlier dependence ----
srt=sorted(rows, key=lambda r:-r["pnl_real"])
top10=sum(r["pnl_real"] for r in srt[:10])
bot10=sum(r["pnl_real"] for r in srt[-10:])
print(f"\n[3. OUTLIER DEPENDENCE]")
print(f"  Top 10 trades P&L : ${top10:,.0f}  ({100*top10/total:.0f}% of total profit)")
print(f"  Worst 10 trades   : ${bot10:,.0f}")
print(f"  Biggest single win: ${srt[0]['pnl_real']:,.0f}  ({srt[0].get('year')})")
print(f"  Biggest single loss: ${srt[-1]['pnl_real']:,.0f}  ({srt[-1].get('year')})")
if top10/total>0.5:
    print(f"  >>> WARNING: >50% of profit from 10 trades. Edge is outlier-dependent/fragile.")
else:
    print(f"  >>> Profit is reasonably distributed, not just a few lucky trades.")

# ---- 4. intervention sensitivity (by year) ----
print(f"\n[4. P&L BY YEAR  (* = known BoJ intervention period)]")
INTERV={2022,2024,2026}
by_year_pnl=defaultdict(float); by_year_n=defaultdict(int)
for r in rows:
    by_year_pnl[r["year"]]+=r["pnl_real"]; by_year_n[r["year"]]+=1
for y in sorted(by_year_pnl):
    flag=" *" if y in INTERV else "  "
    bar_pnl=by_year_pnl[y]
    print(f"  {y}{flag} {by_year_n[y]:>4} trades   ${bar_pnl:>10,.0f}")
interv_pnl=sum(by_year_pnl[y] for y in by_year_pnl if y in INTERV)
other_pnl=sum(by_year_pnl[y] for y in by_year_pnl if y not in INTERV)
print(f"\n  Intervention-year P&L total: ${interv_pnl:,.0f}")
print(f"  Other-year P&L total       : ${other_pnl:,.0f}")
if interv_pnl<0:
    print(f"  >>> UJ LOSES money in intervention years. Structural vulnerability to BoJ.")
else:
    print(f"  >>> UJ survives intervention years on balance (though may be bumpy within).")

# ---- decision summary ----
print(f"\n{'='*70}")
print("DECISION HELP:")
print(f"  - If profit factor < ~1.2, win-rate-thin, AND outlier/intervention dependent")
print(f"    -> UJ's edge is questionable; consider EU-only or restructure.")
print(f"  - If profit factor healthy and distributed -> UJ earns its place; the wide")
print(f"    TP/timeout may just be the strategy's nature (trades exit at expiry near")
print(f"    breakeven, wins come from the moves that do run).")
print(f"  - The expiry % tells you if TP/hold structure is worth re-testing.")
print("="*70)
