#!/usr/bin/env python3
"""Expanded results: T-bill Sharpe, full no-rebalancing table with drift, start-date sensitivity."""
import csv, os, math, json
from collections import OrderedDict
HERE=os.path.dirname(os.path.abspath(__file__))
ALLOC=[0.0,0.05,0.10,0.15,0.20,0.25]

rows=list(csv.reader(open(os.path.join(HERE,'normalised','monthly_series.csv'))))[1:]
M=[r[0] for r in rows]
GOLD={r[0]:float(r[1]) for r in rows}; P={r[0]:float(r[2]) for r in rows}
DIV={r[0]:float(r[3]) for r in rows}; CPI={r[0]:float(r[4]) for r in rows}
BOND={r[0]:float(r[1]) for r in list(csv.reader(open(os.path.join(HERE,'normalised','bond_monthly_returns.csv'))))[1:]}
TBILL={r[0]:float(r[1]) for r in list(csv.reader(open(os.path.join(HERE,'normalised','tbill_monthly_returns.csv'))))[1:]}

R=OrderedDict()
for i in range(1,len(M)):
    a,b=M[i-1],M[i]
    R[b]=((P[b]+DIV[b]/12.0)/P[a]-1.0, BOND[b], GOLD[b]/GOLD[a]-1.0, CPI[b]/CPI[a]-1.0)
ALLK=list(R)

def run(gw, keys, rebal='annual'):
    tgt=[0.60*(1-gw),0.40*(1-gw),gw]; w=list(tgt)
    nom=[]; real=[]; rv=1.0
    for k in keys:
        eq,bd,gd,inf=R[k]; st=sum(w)
        w=[w[0]*(1+eq), w[1]*(1+bd), w[2]*(1+gd)]
        tot=sum(w); nom.append(tot); rv*=(tot/st)/(1+inf); real.append(rv)
        if rebal=='annual' and k.endswith('-12'): w=[tot*t for t in tgt]
    return nom, real, tgt, [x/sum(w) for x in w]

def mets(series):
    n=len(series); yrs=n/12.0
    cagr=series[-1]**(1/yrs)-1
    mr=[series[0]-1]+[series[i]/series[i-1]-1 for i in range(1,n)]
    mu=sum(mr)/n; vol=math.sqrt(sum((x-mu)**2 for x in mr)/(n-1)*12)
    peak=-1e9; mdd=0.0
    for v in series:
        peak=max(peak,v); mdd=min(mdd,v/peak-1)
    return cagr,vol,mdd,series[-1],mr

def sharpe(mr, keys):
    ex=[mr[i]-TBILL[keys[i]] for i in range(len(keys)) if keys[i] in TBILL]
    n=len(ex); mu=sum(ex)/n
    sd=math.sqrt(sum((x-mu)**2 for x in ex)/(n-1))
    return (mu*12)/(sd*math.sqrt(12))

out={}
print('='*96)
print('  EXPANDED RESULTS — %s..%s (%d months)'%(ALLK[0],ALLK[-1],len(ALLK)))
print('='*96)

print('\n[1] SHARPE RECOMPUTED — risk-free = 3-month T-bill (TB3MS, discount->BEY->monthly)')
print('    GS10-proxy Sharpe figures from the earlier run are SUPERSEDED.')
print('%-6s %10s %14s'%('gold','Sharpe','superseded GS10'))
old={0.0:0.380,0.05:0.403,0.10:0.420,0.15:0.430,0.20:0.432,0.25:0.426}
for gw in ALLOC:
    nom,_,_,_=run(gw,ALLK); c,v,d,e,mr=mets(nom)
    s=sharpe(mr,ALLK); out.setdefault(gw,{})['sharpe_tbill']=s
    print('%-6s %10.3f %14.3f'%('%d%%'%(gw*100),s,old[gw]))

print('\n[2] NO-REBALANCING SENSITIVITY — all six allocations, with terminal weight drift')
print('%-6s %8s %8s %8s %10s %28s'%('gold','CAGR','vol','maxDD','$100k ->','ending weights eq/bd/gold'))
for gw in ALLOC:
    nom,_,tgt,endw=run(gw,ALLK,rebal='none'); c,v,d,e,_=mets(nom)
    out[gw].update({'nr_cagr':c,'nr_vol':v,'nr_mdd':d,'nr_end_w':endw})
    print('%-6s %7.2f%% %7.2f%% %7.1f%% %10s   start %2d/%2d/%2d -> %4.1f/%4.1f/%4.1f'
          %('%d%%'%(gw*100),c*100,v*100,d*100,'${:,.0f}'.format(e*100000),
            round(tgt[0]*100),round(tgt[1]*100),round(tgt[2]*100),endw[0]*100,endw[1]*100,endw[2]*100))

print('\n[3] START-DATE SENSITIVITY — identical frozen methodology, same endpoint 2024-06')
print('    Robustness analysis only. Does NOT replace the primary 1968-04 experiment.')
for start in ['1968-05','1973-01','1980-01','1990-01','2000-01']:
    keys=[k for k in ALLK if k>=start]
    print('\n  start %s  (%d months, %.1f years)'%(start,len(keys),len(keys)/12.0))
    print('  %-6s %8s %8s %8s %9s'%('gold','CAGR','vol','maxDD','Sharpe'))
    for gw in ALLOC:
        nom,_,_,_=run(gw,keys); c,v,d,e,mr=mets(nom)
        s=sharpe(mr,keys)
        out[gw].setdefault('start',{})[start]={'cagr':c,'vol':v,'mdd':d,'sharpe':s}
        print('  %-6s %7.2f%% %7.2f%% %7.1f%% %9.3f'%('%d%%'%(gw*100),c*100,v*100,d*100,s))
    cs=[out[g]['start'][start]['cagr'] for g in ALLOC]
    mono_up = all(cs[i]<=cs[i+1] for i in range(len(cs)-1))
    mono_dn = all(cs[i]>=cs[i+1] for i in range(len(cs)-1))
    print('  CAGR ordering vs gold weight: %s'
          %('MONOTONIC INCREASING' if mono_up else 'MONOTONIC DECREASING' if mono_dn else 'NON-MONOTONIC'))

json.dump({str(k):v for k,v in out.items()}, open(os.path.join(HERE,'normalised','results_full.json'),'w'), indent=2, default=float)
print('\nwrote normalised/results_full.json')
