mirror of
https://github.com/tvishia29-alt/FXandRatesDashboard.git
synced 2026-08-23 20:48:04 +00:00
givdatav1
This commit is contained in:
Binary file not shown.
+73
-32
@@ -83,6 +83,35 @@ BOND_ETFS = {
|
|||||||
"GOVT": {"name": "US Total Treasury", "country": "US", "duration": "mixed"},
|
"GOVT": {"name": "US Total Treasury", "country": "US", "duration": "mixed"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ─── EODHD GOVERNMENT BONDS ─────────────────────────────────────────────────
|
||||||
|
EODHD_BONDS = {
|
||||||
|
"US2Y.GBOND": {"key": "us2y", "label": "US 2Y", "country": "US"},
|
||||||
|
"US10Y.GBOND": {"key": "us10y", "label": "US 10Y", "country": "US"},
|
||||||
|
"US30Y.GBOND": {"key": "us30y", "label": "US 30Y", "country": "US"},
|
||||||
|
"UK2Y.GBOND": {"key": "uk2y", "label": "UK 2Y", "country": "UK"},
|
||||||
|
"UK10Y.GBOND": {"key": "uk10y", "label": "UK 10Y", "country": "UK"},
|
||||||
|
"UK30Y.GBOND": {"key": "uk30y", "label": "UK 30Y", "country": "UK"},
|
||||||
|
"DE2Y.GBOND": {"key": "de2y", "label": "Germany 2Y", "country": "Eurozone"},
|
||||||
|
"DE10Y.GBOND": {"key": "de10y", "label": "Germany 10Y", "country": "Eurozone"},
|
||||||
|
"DE30Y.GBOND": {"key": "de30y", "label": "Germany 30Y", "country": "Eurozone"},
|
||||||
|
"JP2Y.GBOND": {"key": "jp2y", "label": "Japan 2Y", "country": "Japan"},
|
||||||
|
"JP10Y.GBOND": {"key": "jp10y", "label": "Japan 10Y", "country": "Japan"},
|
||||||
|
"JP30Y.GBOND": {"key": "jp30y", "label": "Japan 30Y", "country": "Japan"},
|
||||||
|
"IT2Y.GBOND": {"key": "it2y", "label": "Italy 2Y", "country": "Eurozone"},
|
||||||
|
"IT10Y.GBOND": {"key": "it10y", "label": "Italy 10Y", "country": "Eurozone"},
|
||||||
|
"FR10Y.GBOND": {"key": "fr10y", "label": "France 10Y", "country": "Eurozone"},
|
||||||
|
"ES10Y.GBOND": {"key": "es10y", "label": "Spain 10Y", "country": "Eurozone"},
|
||||||
|
"CA2Y.GBOND": {"key": "ca2y", "label": "Canada 2Y", "country": "Canada"},
|
||||||
|
"CA10Y.GBOND": {"key": "ca10y", "label": "Canada 10Y", "country": "Canada"},
|
||||||
|
"AU2Y.GBOND": {"key": "au2y", "label": "Australia 2Y", "country": "Australia"},
|
||||||
|
"AU10Y.GBOND": {"key": "au10y", "label": "Australia 10Y", "country": "Australia"},
|
||||||
|
"NZ2Y.GBOND": {"key": "nz2y", "label": "New Zealand 2Y", "country": "New Zealand"},
|
||||||
|
"NZ10Y.GBOND": {"key": "nz10y", "label": "New Zealand 10Y", "country": "New Zealand"},
|
||||||
|
"SW10Y.GBOND": {"key": "ch10y", "label": "Switzerland 10Y", "country": "Switzerland"},
|
||||||
|
"SE10Y.GBOND": {"key": "se10y", "label": "Sweden 10Y", "country": "Sweden"},
|
||||||
|
"NO10Y.GBOND": {"key": "no10y", "label": "Norway 10Y", "country": "Norway"},
|
||||||
|
}
|
||||||
|
|
||||||
# ─── COMMODITY TICKERS ───────────────────────────────────────────────────────
|
# ─── COMMODITY TICKERS ───────────────────────────────────────────────────────
|
||||||
COMMODITIES = {
|
COMMODITIES = {
|
||||||
"GC=F": {"key": "gold", "name": "Gold", "unit": "$/oz"},
|
"GC=F": {"key": "gold", "name": "Gold", "unit": "$/oz"},
|
||||||
@@ -140,25 +169,36 @@ FX_PAIRS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def fetch_gov_data(endpoint, params=None):
|
def fetch_eodhd_eod(symbol):
|
||||||
"""Fetch data from the government API."""
|
"""Fetch latest EOD data from EODHD for a bond/rate symbol."""
|
||||||
if not GOV_KEY:
|
if not GOV_KEY:
|
||||||
print(" GOV API key missing")
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if params is None:
|
|
||||||
params = {}
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
base_url = "https://YOUR-GOV-API-ENDPOINT-HERE"
|
url = f"https://eodhd.com/api/eod/{symbol}"
|
||||||
params["api_key"] = GOV_KEY
|
params = {"api_token": GOV_KEY, "fmt": "json", "order": "d", "limit": 2}
|
||||||
|
r = requests.get(url, params=params, timeout=15)
|
||||||
r = requests.get(base_url + endpoint, params=params, timeout=15)
|
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return r.json()
|
data = r.json()
|
||||||
|
if not isinstance(data, list) or len(data) < 1:
|
||||||
|
return None
|
||||||
|
latest = data[0]
|
||||||
|
prev = data[1] if len(data) >= 2 else None
|
||||||
|
value = latest.get("close")
|
||||||
|
prev_value = prev.get("close") if prev else None
|
||||||
|
change = round(value - prev_value, 4) if value is not None and prev_value is not None else None
|
||||||
|
pct_change = (
|
||||||
|
round((value - prev_value) / prev_value * 100, 4)
|
||||||
|
if value is not None and prev_value is not None and prev_value != 0
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
"value": value,
|
||||||
|
"change": change,
|
||||||
|
"pct_change": pct_change,
|
||||||
|
"date": latest.get("date"),
|
||||||
|
}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" Government API error ({endpoint}): {e}")
|
print(f" EODHD error ({symbol}): {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@@ -477,6 +517,7 @@ def main():
|
|||||||
"macro": {},
|
"macro": {},
|
||||||
"sentiment": {},
|
"sentiment": {},
|
||||||
"scenarios": {},
|
"scenarios": {},
|
||||||
|
"gov_bonds": {},
|
||||||
}
|
}
|
||||||
|
|
||||||
# 1. US YIELD CURVE from FRED (most reliable)
|
# 1. US YIELD CURVE from FRED (most reliable)
|
||||||
@@ -663,24 +704,23 @@ def main():
|
|||||||
}]
|
}]
|
||||||
print(f" Final calendar rows: {len(output['calendar'])}")
|
print(f" Final calendar rows: {len(output['calendar'])}")
|
||||||
|
|
||||||
# 11. Government API data
|
# 11. Government bonds (EODHD)
|
||||||
print("\n[11] Fetching government data...")
|
print("\n[11] Fetching government bonds from EODHD...")
|
||||||
gov_data = fetch_gov_data("/some/endpoint", params={"country": "US"})
|
if GOV_KEY:
|
||||||
if gov_data:
|
for symbol, info in EODHD_BONDS.items():
|
||||||
output["policy_rates"]["US"] = gov_data.get("policy_rate")
|
result = fetch_eodhd_eod(symbol)
|
||||||
|
if result:
|
||||||
output["macro"]["US"] = {
|
result["label"] = info["label"]
|
||||||
"cpi": f"{gov_data.get('cpi_yoy')}%" if gov_data.get("cpi_yoy") is not None else "\u2014",
|
result["country"] = info["country"]
|
||||||
"cpiP": "\u2014",
|
output["gov_bonds"][info["key"]] = result
|
||||||
"gdp": f"{gov_data.get('gdp_qoq')}%" if gov_data.get("gdp_qoq") is not None else "\u2014",
|
v = result["value"]
|
||||||
"gdpT": "QoQ",
|
c = result.get("change")
|
||||||
"unemp": f"{gov_data.get('unemployment')}%" if gov_data.get("unemployment") is not None else "\u2014",
|
chg_str = f" ({c:+.3f})" if c is not None else ""
|
||||||
"unempT": "latest",
|
print(f" {info['label']}: {v}%{chg_str}")
|
||||||
"stance": "\u2014",
|
time.sleep(0.3) # Rate limit
|
||||||
"last": "\u2014",
|
print(f" Fetched {len(output['gov_bonds'])} bonds")
|
||||||
"next": "\u2014",
|
else:
|
||||||
"pricing": "\u2014",
|
print(" EODHD API key not set — skipping government bonds")
|
||||||
}
|
|
||||||
|
|
||||||
# Write output
|
# Write output
|
||||||
output_path = Path(OUTPUT_FILE)
|
output_path = Path(OUTPUT_FILE)
|
||||||
@@ -696,6 +736,7 @@ def main():
|
|||||||
print(f" FX: {len(output['fx'])} pairs")
|
print(f" FX: {len(output['fx'])} pairs")
|
||||||
print(f" News: {len(output['news'])} articles")
|
print(f" News: {len(output['news'])} articles")
|
||||||
print(f" Calendar: {len(output['calendar'])} events")
|
print(f" Calendar: {len(output['calendar'])} events")
|
||||||
|
print(f" Gov bonds: {len(output['gov_bonds'])} instruments")
|
||||||
print(f"{'=' * 60}")
|
print(f"{'=' * 60}")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+9
-4
@@ -35,6 +35,7 @@ const pOf={US:"DXY",Eurozone:"EURUSD",UK:"GBPUSD",Japan:"USDJPY",Switzerland:"US
|
|||||||
const nKw={US:["fed","fomc","treasury","dollar","powell","nonfarm"],Eurozone:["ecb","lagarde","eurozone","bund"],UK:["boe","bailey","gilt","sterling","uk gdp","uk cpi"],Japan:["boj","ueda","yen","jgb","japan"],Switzerland:["snb","swiss","franc"],Australia:["rba","aussie","australia"],Canada:["boc","canada","loonie"],"New Zealand":["rbnz","kiwi","new zealand"],Sweden:["riksbank","sweden"],Norway:["norges","norway"],Brazil:["bcb","brazil","real"],Mexico:["banxico","mexico","peso"],"South Africa":["sarb","south africa","rand"],India:["rbi","india","rupee"],"South Korea":["bok","korea","won"],Turkey:["cbrt","turkey","lira"],Poland:["nbp","poland","zloty"]};
|
const nKw={US:["fed","fomc","treasury","dollar","powell","nonfarm"],Eurozone:["ecb","lagarde","eurozone","bund"],UK:["boe","bailey","gilt","sterling","uk gdp","uk cpi"],Japan:["boj","ueda","yen","jgb","japan"],Switzerland:["snb","swiss","franc"],Australia:["rba","aussie","australia"],Canada:["boc","canada","loonie"],"New Zealand":["rbnz","kiwi","new zealand"],Sweden:["riksbank","sweden"],Norway:["norges","norway"],Brazil:["bcb","brazil","real"],Mexico:["banxico","mexico","peso"],"South Africa":["sarb","south africa","rand"],India:["rbi","india","rupee"],"South Korea":["bok","korea","won"],Turkey:["cbrt","turkey","lira"],Poland:["nbp","poland","zloty"]};
|
||||||
|
|
||||||
const MD={};
|
const MD={};
|
||||||
|
const bondPfx={"US":["us"],"UK":["uk"],"Eurozone":["de","it","fr","es"],"Japan":["jp"],"Canada":["ca"],"Australia":["au"],"New Zealand":["nz"],"Switzerland":["ch"],"Sweden":["se"],"Norway":["no"]};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -221,8 +222,9 @@ function Scenarios({risk,yld,g10,em,cmd}){
|
|||||||
function CorrMx(){return <div><div style={{marginBottom:12}}><span style={{color:C.ac,fontSize:13,fontWeight:700}}>30-Day Correlation Matrix</span></div><div style={{padding:40,textAlign:"center",color:C.txM,fontSize:12,border:"1px dashed "+C.bd,borderRadius:6}}>—<br/><span style={{fontSize:11,marginTop:8,display:"inline-block"}}>Correlation data not available — requires a live feed</span></div></div>}
|
function CorrMx(){return <div><div style={{marginBottom:12}}><span style={{color:C.ac,fontSize:13,fontWeight:700}}>30-Day Correlation Matrix</span></div><div style={{padding:40,textAlign:"center",color:C.txM,fontSize:12,border:"1px dashed "+C.bd,borderRadius:6}}>—<br/><span style={{fontSize:11,marginTop:8,display:"inline-block"}}>Correlation data not available — requires a live feed</span></div></div>}
|
||||||
|
|
||||||
/* ═══ DEEP DIVE ═══════════════════════════════════════════════════ */
|
/* ═══ DEEP DIVE ═══════════════════════════════════════════════════ */
|
||||||
function Deep({ctry,g10,em,yld,news,nL,risk,macro,policyRates}){
|
function Deep({ctry,g10,em,yld,news,nL,risk,macro,policyRates,govBonds}){
|
||||||
const ccy=cOf[ctry],fp=[...g10,...em].find(x=>x.pair===pOf[ctry]),y=yld[ctry]||{},tpl=RT.find(x=>x.c===ctry),m=macro?.[ctry]||{},cbRate=policyRates?.[ctry]??null;
|
const ccy=cOf[ctry],fp=[...g10,...em].find(x=>x.pair===pOf[ctry]),y=yld[ctry]||{},tpl=RT.find(x=>x.c===ctry),m=macro?.[ctry]||{},cbRate=policyRates?.[ctry]??null;
|
||||||
|
const pfxList=bondPfx[ctry]||[];const cBonds=Object.entries(govBonds||{}).filter(([k])=>pfxList.some(p=>k.startsWith(p))).map(([k,v])=>({key:k,...v}));
|
||||||
const kws=nKw[ctry]||[ccy.toLowerCase()];const cN=news.filter(n=>kws.some(kw=>(n.headline||"").toLowerCase().includes(kw)));const dN=cN.length>=2?cN:news;
|
const kws=nKw[ctry]||[ccy.toLowerCase()];const cN=news.filter(n=>kws.some(kw=>(n.headline||"").toLowerCase().includes(kw)));const dN=cN.length>=2?cN:news;
|
||||||
const ce=Object.entries(y).filter(([k,v])=>v!=null&&k.startsWith("y")).map(([k,v])=>[k.replace("y","").toUpperCase(),v]);
|
const ce=Object.entries(y).filter(([k,v])=>v!=null&&k.startsWith("y")).map(([k,v])=>[k.replace("y","").toUpperCase(),v]);
|
||||||
const [ai,setAi]=useState(null);
|
const [ai,setAi]=useState(null);
|
||||||
@@ -252,6 +254,7 @@ function Deep({ctry,g10,em,yld,news,nL,risk,macro,policyRates}){
|
|||||||
} : null,
|
} : null,
|
||||||
macro: m,
|
macro: m,
|
||||||
riskBar: risk,
|
riskBar: risk,
|
||||||
|
govBonds: cBonds,
|
||||||
headlines: dN.slice(0, 8).map(n => ({
|
headlines: dN.slice(0, 8).map(n => ({
|
||||||
headline: n.headline,
|
headline: n.headline,
|
||||||
source: n.source,
|
source: n.source,
|
||||||
@@ -435,6 +438,8 @@ function Deep({ctry,g10,em,yld,news,nL,risk,macro,policyRates}){
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{cBonds.length>0&&<div style={{background:C.bgC,border:"1px solid "+C.bd,borderRadius:8,padding:16,marginTop:16}}><div style={{color:C.tx,fontSize:14,fontWeight:700,marginBottom:10}}>🏦 Government Bonds</div><Tbl cols={[{k:"label",l:"Bond",a:"left",nm:1,cl:()=>C.b},{k:"value",l:"Yield %",rn:r=>r.value!=null?Number(r.value).toFixed(3):"\u2014"},{k:"change",l:"Chg (bp)",rn:r=>r.change!=null?fb(r.change*100):"\u2014",cl:r=>cc(r.change)},{k:"date",l:"Date",a:"left",cl:()=>C.txM}]} rows={cBonds} sm/></div>}
|
||||||
|
|
||||||
<div className="g3" style={{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:16,marginTop:16}}>
|
<div className="g3" style={{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:16,marginTop:16}}>
|
||||||
<div style={{background:C.bgC,border:"1px solid "+C.bd,borderRadius:8,padding:16}}>
|
<div style={{background:C.bgC,border:"1px solid "+C.bd,borderRadius:8,padding:16}}>
|
||||||
<div style={{color:C.tx,fontSize:13,fontWeight:700,marginBottom:10}}>Central Bank</div>
|
<div style={{color:C.tx,fontSize:13,fontWeight:700,marginBottom:10}}>Central Bank</div>
|
||||||
@@ -508,14 +513,14 @@ function App(){
|
|||||||
const [rL,sRL]=useState(false);const [cal,sCal]=useState([]);const [cL,sCL]=useState(false);const [news,sNews]=useState([]);const [nL,sNL]=useState(false);
|
const [rL,sRL]=useState(false);const [cal,sCal]=useState([]);const [cL,sCL]=useState(false);const [news,sNews]=useState([]);const [nL,sNL]=useState(false);
|
||||||
const [cmd,sCmd]=useState({gold:{},wti:{},brent:{}});const [ld,sLd]=useState(false);const [lr,sLR]=useState(null);
|
const [cmd,sCmd]=useState({gold:{},wti:{},brent:{}});const [ld,sLd]=useState(false);const [lr,sLR]=useState(null);
|
||||||
const [etfs,setEtfs]=useState({});const [vol,setVol]=useState({});const [bondEtfs,setBondEtfs]=useState({});
|
const [etfs,setEtfs]=useState({});const [vol,setVol]=useState({});const [bondEtfs,setBondEtfs]=useState({});
|
||||||
const [macro,setMacro]=useState({});const [policyRates,setPolicyRates]=useState({});
|
const [macro,setMacro]=useState({});const [policyRates,setPolicyRates]=useState({});const [govBonds,setGovBonds]=useState({});
|
||||||
const svK=useCallback(nk=>{setKeys(nk);Object.entries(nk).forEach(([k,v])=>sk(k,v))},[]);
|
const svK=useCallback(nk=>{setKeys(nk);Object.entries(nk).forEach(([k,v])=>sk(k,v))},[]);
|
||||||
const load=useCallback(async()=>{
|
const load=useCallback(async()=>{
|
||||||
sLd(true);
|
sLd(true);
|
||||||
try{
|
try{
|
||||||
const data=await fData();
|
const data=await fData();
|
||||||
setEtfs(data.etfs||{});setVol(data.volatility||{});setBondEtfs(data.bond_etfs||{});
|
setEtfs(data.etfs||{});setVol(data.volatility||{});setBondEtfs(data.bond_etfs||{});
|
||||||
setMacro(data.macro||{});setPolicyRates(data.policy_rates||{});
|
setMacro(data.macro||{});setPolicyRates(data.policy_rates||{});setGovBonds(data.gov_bonds||{});
|
||||||
const mapFx=defs=>defs.map(d=>{const x=data.fx?.[d.p];return{pair:d.p,spot:x?.price??null,d1:x?.d1_pct??null,w1:x?.w1_pct??null,m1:x?.m1_pct??null,ytd:null}});
|
const mapFx=defs=>defs.map(d=>{const x=data.fx?.[d.p];return{pair:d.p,spot:x?.price??null,d1:x?.d1_pct??null,w1:x?.w1_pct??null,m1:x?.m1_pct??null,ytd:null}});
|
||||||
sG10(mapFx(G10));sEM(mapFx(EMP));sFxL(true);
|
sG10(mapFx(G10));sEM(mapFx(EMP));sFxL(true);
|
||||||
const mappedYields={};
|
const mappedYields={};
|
||||||
@@ -544,7 +549,7 @@ function App(){
|
|||||||
{sec==="commod"&&<div style={{background:C.bgC,border:"1px solid "+C.bd,borderRadius:8,padding:16}}><div style={{color:C.tx,fontSize:15,fontWeight:700,marginBottom:12}}>Commodities</div><Cmdt d={cmd}/></div>}
|
{sec==="commod"&&<div style={{background:C.bgC,border:"1px solid "+C.bd,borderRadius:8,padding:16}}><div style={{color:C.tx,fontSize:15,fontWeight:700,marginBottom:12}}>Commodities</div><Cmdt d={cmd}/></div>}
|
||||||
{sec==="scenarios"&&<Scenarios risk={risk} yld={yld} g10={g10D} em={emD} cmd={cmd}/>}
|
{sec==="scenarios"&&<Scenarios risk={risk} yld={yld} g10={g10D} em={emD} cmd={cmd}/>}
|
||||||
{sec==="corr"&&<div style={{background:C.bgC,border:"1px solid "+C.bd,borderRadius:8,padding:20}}><CorrMx/></div>}
|
{sec==="corr"&&<div style={{background:C.bgC,border:"1px solid "+C.bd,borderRadius:8,padding:20}}><CorrMx/></div>}
|
||||||
{sec==="deep"&&<div><div style={{display:"flex",flexWrap:"wrap",gap:4,marginBottom:16}}>{RT.map(c=><button key={c.c} onClick={()=>setCtry(c.c)} style={{padding:"6px 12px",fontSize:11,fontWeight:600,borderRadius:4,background:ctry===c.c?C.ac+"25":C.bgC,color:ctry===c.c?C.ac:C.txD,border:"1px solid "+(ctry===c.c?C.ac+"50":C.bd)}}>{c.f} {c.c}</button>)}</div><Deep ctry={ctry} g10={g10D} em={emD} yld={yld} news={news} nL={nL} risk={risk} macro={macro} policyRates={policyRates}/></div>}
|
{sec==="deep"&&<div><div style={{display:"flex",flexWrap:"wrap",gap:4,marginBottom:16}}>{RT.map(c=><button key={c.c} onClick={()=>setCtry(c.c)} style={{padding:"6px 12px",fontSize:11,fontWeight:600,borderRadius:4,background:ctry===c.c?C.ac+"25":C.bgC,color:ctry===c.c?C.ac:C.txD,border:"1px solid "+(ctry===c.c?C.ac+"50":C.bd)}}>{c.f} {c.c}</button>)}</div><Deep ctry={ctry} g10={g10D} em={emD} yld={yld} news={news} nL={nL} risk={risk} macro={macro} policyRates={policyRates} govBonds={govBonds}/></div>}
|
||||||
{sec==="cal"&&<div style={{background:C.bgC,border:"1px solid "+C.bd,borderRadius:8,padding:16}}><div style={{marginBottom:12}}><span style={{color:C.tx,fontSize:15,fontWeight:700}}>Economic Calendar</span></div><Cal evts={cal} live={cL}/></div>}
|
{sec==="cal"&&<div style={{background:C.bgC,border:"1px solid "+C.bd,borderRadius:8,padding:16}}><div style={{marginBottom:12}}><span style={{color:C.tx,fontSize:15,fontWeight:700}}>Economic Calendar</span></div><Cal evts={cal} live={cL}/></div>}
|
||||||
</div>
|
</div>
|
||||||
<div style={{textAlign:"center",padding:"12px 0",borderTop:"1px solid "+C.bd+"20"}}><span style={{color:C.txM,fontSize:10}}>FX RADAR v4 · <Dot on={fxL}/>{fxL?"Live":"..."}</span></div>
|
<div style={{textAlign:"center",padding:"12px 0",borderTop:"1px solid "+C.bd+"20"}}><span style={{color:C.txM,fontSize:10}}>FX RADAR v4 · <Dot on={fxL}/>{fxL?"Live":"..."}</span></div>
|
||||||
|
|||||||
Reference in New Issue
Block a user