#!/usr/bin/env python3
"""Trade frequency and risk simulation for production hybrid journal.

Outputs:
- trades per strategy per day
- trades per strategy per ISO week
- equity/margin-call risk with current fixed-$100 per R model
- simulation with max daily loss cap = 30% of start-of-day equity
"""
from __future__ import annotations
import json, statistics
from collections import Counter, defaultdict
from datetime import datetime, timezone
from pathlib import Path
ROOT=Path(__file__).resolve().parents[1]
JOURNAL=ROOT/'data/journal.json'
OUT_JSON=ROOT/'reports/risk_trade_frequency_analysis.json'
OUT_DAILY=ROOT/'reports/trades_per_strategy_daily.csv'
OUT_WEEKLY=ROOT/'reports/trades_per_strategy_weekly.csv'
def parse_dt(s):
    dt=datetime.fromisoformat(str(s).replace('Z','+00:00'))
    if dt.tzinfo is None: dt=dt.replace(tzinfo=timezone.utc)
    return dt.astimezone(timezone.utc)
def load_trades():
    tr=json.loads(JOURNAL.read_text())['trades']
    return sorted(tr,key=lambda x:x['timestamp'])
def equity_stats(trades, daily_cap_pct=None, start=10000.0, risk_per_r=100.0):
    eq=start; peak=eq; maxdd=0.0; maxdd_pct=0.0; margin_call=False; min_eq=eq
    skipped=[]; executed=[]; day_start_eq=None; day=None; day_loss=0.0
    daily_rows=defaultdict(lambda:{'executed':0,'skipped':0,'r':0.0,'loss_usd':0.0,'start_eq':None,'end_eq':None})
    for t in trades:
        dt=parse_dt(t['timestamp']); d=dt.date().isoformat()
        if d!=day:
            if day is not None: daily_rows[day]['end_eq']=eq
            day=d; day_start_eq=eq; day_loss=0.0; daily_rows[d]['start_eq']=eq
        realized_r=float(t['r']); pnl=realized_r*risk_per_r
        cap_hit=False
        if daily_cap_pct is not None and pnl<0:
            # If taking this loss would push realized day loss beyond cap, skip all further losing trades that violate cap.
            projected_loss=day_loss + (-pnl)
            if projected_loss > day_start_eq*daily_cap_pct:
                cap_hit=True
        if cap_hit:
            skipped.append(t); daily_rows[d]['skipped']+=1; continue
        eq += pnl; executed.append(t); daily_rows[d]['executed']+=1; daily_rows[d]['r']+=realized_r
        if pnl<0: day_loss += -pnl; daily_rows[d]['loss_usd']+=-pnl
        peak=max(peak,eq); dd=peak-eq; dd_pct=dd/peak*100 if peak else 0
        maxdd=max(maxdd,dd); maxdd_pct=max(maxdd_pct,dd_pct); min_eq=min(min_eq,eq)
        if eq<=0: margin_call=True
    if day is not None: daily_rows[day]['end_eq']=eq
    c=Counter(t['outcome'] for t in executed); rs=[float(t['r']) for t in executed]
    return {'start_equity':start,'final_equity':round(eq,2),'min_equity':round(min_eq,2),'peak_equity':round(peak,2),'margin_call':margin_call,'executed_trades':len(executed),'skipped_trades':len(skipped),'wins':c.get('Win',0),'losses':c.get('Loss',0),'winrate':round(c.get('Win',0)/len(executed)*100,2) if executed else 0,'net_R':round(sum(rs),2) if rs else 0,'avg_R':round(statistics.mean(rs),3) if rs else 0,'maxDD_usd':round(maxdd,2),'maxDD_pct_peak':round(maxdd_pct,2),'daily_rows':daily_rows}
def main():
    trades=load_trades(); strategies=sorted(set(t['strategy'] for t in trades))
    daily=defaultdict(Counter); weekly=defaultdict(Counter)
    for t in trades:
        dt=parse_dt(t['timestamp']); d=dt.date().isoformat(); y,w,_=dt.isocalendar(); wk=f'{y}-W{w:02d}'
        daily[d][t['strategy']]+=1; weekly[wk][t['strategy']]+=1
    # CSV outputs
    OUT_DAILY.write_text('date,'+','.join(strategies)+',total\n'+'\n'.join([d+','+','.join(str(daily[d].get(s,0)) for s in strategies)+','+str(sum(daily[d].values())) for d in sorted(daily)])+'\n')
    OUT_WEEKLY.write_text('week,'+','.join(strategies)+',total\n'+'\n'.join([w+','+','.join(str(weekly[w].get(s,0)) for s in strategies)+','+str(sum(weekly[w].values())) for w in sorted(weekly)])+'\n')
    base=equity_stats(trades,None); capped=equity_stats(trades,0.30)
    # aggregate daily/weekly summary stats
    daily_totals=[sum(c.values()) for c in daily.values()]; weekly_totals=[sum(c.values()) for c in weekly.values()]
    strat_daily_avg={s:round(statistics.mean([daily[d].get(s,0) for d in daily]),2) for s in strategies}
    strat_weekly_avg={s:round(statistics.mean([weekly[w].get(s,0) for w in weekly]),2) for s in strategies}
    out={'metadata':{'source':str(JOURNAL),'generated_at':datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace('+00:00','Z'),'risk_per_R_usd':100,'daily_loss_cap_test':'30% of start-of-day equity'},'trade_count':len(trades),'strategy_total_counts':dict(Counter(t['strategy'] for t in trades)),'daily':{'days':len(daily),'avg_trades_per_day':round(statistics.mean(daily_totals),2),'max_trades_per_day':max(daily_totals),'strategy_avg_per_day':strat_daily_avg,'csv':str(OUT_DAILY.relative_to(ROOT))},'weekly':{'weeks':len(weekly),'avg_trades_per_week':round(statistics.mean(weekly_totals),2),'max_trades_per_week':max(weekly_totals),'strategy_avg_per_week':strat_weekly_avg,'csv':str(OUT_WEEKLY.relative_to(ROOT))},'baseline_no_daily_cap':{k:v for k,v in base.items() if k!='daily_rows'},'with_daily_loss_cap_30pct':{k:v for k,v in capped.items() if k!='daily_rows'},'max_daily_loss_baseline_usd':round(max(v['loss_usd'] for v in base['daily_rows'].values()),2),'max_daily_loss_baseline_pct_of_day_start':round(max((v['loss_usd']/(v['start_eq'] or 1))*100 for v in base['daily_rows'].values()),2),'days_cap_would_skip':sum(1 for v in capped['daily_rows'].values() if v['skipped']>0)}
    OUT_JSON.write_text(json.dumps(out,indent=2,ensure_ascii=False)+'\n')
    print(json.dumps(out,indent=2))
if __name__=='__main__': main()
