diff --git a/index.html b/index.html
index 8e7f8a4..a46f4b4 100644
--- a/index.html
+++ b/index.html
@@ -2,7 +2,7 @@
-FX RADAR TEST v4
+FX RADAR TEST v5
@@ -48,7 +48,7 @@ function RiskBar({d,live}){const vd=(d.VIX?.chg||0)<0,dd=(d.DXY?.chg||0)<0,on=vd
/* ═══ PAGES ═══════════════════════════════════════════════════════ */
function FxTbl({data,live}){return {live?"Live via Frankfurter":"Loading..."}
C.b},{k:"spot",l:"Spot",rn:r=>r.spot!=null?Number(r.spot).toFixed(r.spot>100?2:4):"—"},{k:"d1",l:"1D %",rn:r=>fc(r.d1),cl:r=>cc(r.d1)},{k:"w1",l:"1W %",rn:r=>fc(r.w1),cl:r=>cc(r.w1)},{k:"m1",l:"1M %",rn:r=>fc(r.m1),cl:r=>cc(r.m1)},{k:"ytd",l:"YTD %",rn:r=>fc(r.ytd),cl:r=>cc(r.ytd)}]} rows={data}/> }
-function YldTbl({yld,live}){return {live?"US via FRED · EU via ECB":"No yield data"}
r.f+" "+r.c},{k:"cb",l:"CB Rate",rn:r=>r.cb!=null?r.cb.toFixed(2)+"%":"—",cl:r=>r.cb!=null?C.tx:C.txM},{k:"y2",l:"2Y",rn:r=>r.y2!=null?r.y2.toFixed(2):"—",cl:r=>r.y2?C.tx:C.txM},{k:"y10",l:"10Y",rn:r=>r.y10!=null?r.y10.toFixed(2):"—",cl:r=>r.y10?C.tx:C.txM},{k:"s",l:"2s10s",rn:r=>r.y2&&r.y10?fb((r.y10-r.y2)*100):"—",cl:r=>r.y2&&r.y10?cc(r.y10-r.y2):C.txM}]} rows={RT.map(r=>({...r,...(yld[r.c]||{})}))} sm/> }
+function YldTbl({yld,live,policyRates}){return {live?"US via FRED · EU via ECB":"No yield data"}
r.f+" "+r.c},{k:"cb",l:"CB Rate",rn:r=>r.cb!=null?r.cb.toFixed(2)+"%":"—",cl:r=>r.cb!=null?C.tx:C.txM},{k:"y2",l:"2Y",rn:r=>r.y2!=null?r.y2.toFixed(2):"—",cl:r=>r.y2?C.tx:C.txM},{k:"y10",l:"10Y",rn:r=>r.y10!=null?r.y10.toFixed(2):"—",cl:r=>r.y10?C.tx:C.txM},{k:"s",l:"2s10s",rn:r=>r.y2&&r.y10?fb((r.y10-r.y2)*100):"—",cl:r=>r.y2&&r.y10?cc(r.y10-r.y2):C.txM}]} rows={RT.map(r=>({...r,cb:policyRates?.[r.c]??null,...(yld[r.c]||{})}))} sm/> }
function Cmdt({d}){const items=[{k:"gold",l:"Gold XAU",s:"TVC:GOLD"},{k:"wti",l:"WTI Crude",s:"TVC:USOIL"},{k:"brent",l:"Brent",s:"TVC:UKOIL"}];return {items.map(it=>{const v=d[it.k];return
{it.l}
{v?.level!=null?"$"+Number(v.level).toLocaleString(undefined,{maximumFractionDigits:2}):"—"}
{v?.chg!=null&&
{fc(v.chg)}
}
})}
}
function XCry({yld}){const g=RT.filter(r=>["US","Eurozone","UK","Japan","Switzerland","Australia","New Zealand","Canada","Sweden","Norway"].includes(r.c));const gY=c=>yld[c]?.y2??null;const pairs=[];for(let i=0;iyb?a:b,sc=ya>yb?b:a;pairs.push({lc:lc.ccy,sc:sc.ccy,lf:lc.f,sf:sc.f,ly:Math.max(ya,yb),sy:Math.min(ya,yb),carry:d})}if(!pairs.length)return Carry data requires live yield feeds (FRED / ECB)
;return r.rk<=5?C.g:C.txD},{k:"t",l:"Trade",a:"left",nm:1,rn:r=>r.lf+" Long "+r.lc+" / "+r.sf+" Short "+r.sc},{k:"ly",l:"Long Yld",rn:r=>r.ly.toFixed(2)+"%"},{k:"sy",l:"Short Yld",rn:r=>r.sy.toFixed(2)+"%"},{k:"carry",l:"Carry",rn:r=>"+"+r.carry.toFixed(2)+"%",cl:r=>r.carry>3?C.g:r.carry>1?C.tl:C.txD},{k:"bp",l:"bps",rn:r=>"+"+(r.carry*100).toFixed(0),cl:r=>r.carry>3?C.g:r.carry>1?C.tl:C.txD}]} rows={pairs.sort((a,b)=>b.carry-a.carry).map((r,i)=>({...r,rk:i+1}))} sm/>}
function UCry({yld}){const uY=yld.US?.y2;if(uY==null)return Carry data requires live US yield feed (FRED)
;const rows=RT.filter(r=>r.c!=="US").map(r=>{const ry=yld[r.c]?.y2;return {...r,carry:ry!=null?+((ry-uY).toFixed(2)):null}}).filter(r=>r.carry!=null).sort((a,b)=>b.carry-a.carry).map((r,i)=>({...r,rk:i+1}));if(!rows.length)return No foreign yield data available yet
;return r.rk<=3?C.g:r.rk>=13?C.r:C.txD},{k:"c",l:"Currency",a:"left",nm:1,rn:r=>r.f+" "+r.ccy},{k:"y",l:"2Y Yield",rn:r=>(yld[r.c]?.y2!=null?yld[r.c].y2.toFixed(2)+"%":"—")},{k:"carry",l:"vs USD",rn:r=>fc(r.carry),cl:r=>cc(r.carry)},{k:"dir",l:"Direction",a:"left",nm:1,rn:r=>r.carry>0.3?"Long "+r.ccy:"Short "+r.ccy,cl:r=>r.carry>0.3?C.g:C.r}]} rows={rows} sm/>}
@@ -56,7 +56,7 @@ function CarryP({yld}){const [t,sT]=useState("Cross G10");return ({name,price:v?.price??null,d1:v?.d1_pct??null,w1:v?.w1_pct??null,m1:v?.m1_pct??null}));if(!rows.length)return No ETF data available
;return C.b},{k:"price",l:"Price",rn:r=>r.price!=null?Number(r.price).toFixed(2):"—"},{k:"d1",l:"1D %",rn:r=>fc(r.d1),cl:r=>cc(r.d1)},{k:"w1",l:"1W %",rn:r=>fc(r.w1),cl:r=>cc(r.w1)},{k:"m1",l:"1M %",rn:r=>fc(r.m1),cl:r=>cc(r.m1)}]} rows={rows}/>}
function VolTbl({vol}){const rows=Object.entries(vol||{}).map(([name,v])=>({name,price:v?.price??null,prev:v?.prev_close??null,chg:v?.change_pct??null}));if(!rows.length)return No volatility data available
;return C.b},{k:"price",l:"Level",rn:r=>r.price!=null?Number(r.price).toFixed(2):"—"},{k:"prev",l:"Prev",rn:r=>r.prev!=null?Number(r.prev).toFixed(2):"—"},{k:"chg",l:"Change",rn:r=>r.chg!=null?fc(r.chg,""):"—",cl:r=>cc(r.chg)}]} rows={rows}/>}
function BondEtfTbl({bondEtfs}){const rows=Object.entries(bondEtfs||{}).map(([name,v])=>({name,country:v?.country??"",duration:v?.duration??"",price:v?.price??null,d1:v?.d1_pct??null,w1:v?.w1_pct??null,m1:v?.m1_pct??null}));if(!rows.length)return No bond ETF data available
;return C.b},{k:"country",l:"Country",a:"left"},{k:"duration",l:"Duration",a:"left"},{k:"price",l:"Price",rn:r=>r.price!=null?Number(r.price).toFixed(2):"—"},{k:"d1",l:"1D %",rn:r=>fc(r.d1),cl:r=>cc(r.d1)},{k:"w1",l:"1W %",rn:r=>fc(r.w1),cl:r=>cc(r.w1)},{k:"m1",l:"1M %",rn:r=>fc(r.m1),cl:r=>cc(r.m1)}]} rows={rows} sm/>}
-function Markets({g10,em,fxL,yld,yL,etfs,vol,bondEtfs}){const [t,sT]=useState("G10 FX");return {t==="G10 FX"&&}{t==="EM FX"&&}{t==="Rates"&&}{t==="Carry"&&}{t==="ETFs"&&}{t==="Volatility"&&}{t==="Bond ETFs"&&}
}
+function Markets({g10,em,fxL,yld,yL,etfs,vol,bondEtfs,policyRates}){const [t,sT]=useState("G10 FX");return {t==="G10 FX"&&}{t==="EM FX"&&}{t==="Rates"&&}{t==="Carry"&&}{t==="ETFs"&&}{t==="Volatility"&&}{t==="Bond ETFs"&&}
}
/* ═══ SENTIMENT GAUGE ═════════════════════════════════════════════ */
function calcSentiment(risk,g10,em,cmd){
@@ -545,7 +545,7 @@ function App(){
{sec==="brief"&&
}
{sec==="sentiment"&&}
- {sec==="markets"&&
}
+ {sec==="markets"&&
}
{sec==="commod"&&}
{sec==="scenarios"&&}
{sec==="corr"&&
}