alphaforge-pro / index.html
Premchan369's picture
Upload index.html
bb84d61 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>AlphaForge Pro</title>
<script src="https://cdn.plot.ly/plotly-2.35.2.min.js"></script>
<style>
:root{--bg:#0a0e17;--card:#111827;--accent:#38bdf8;--green:#10b981;--red:#ef4444;--yellow:#f59e0b;--text:#94a3b8;--bright:#e2e8f0;--border:#1e293b}
*{margin:0;padding:0;box-sizing:border-box}
body{background:var(--bg);color:var(--text);font-family:-apple-system,BlinkMacSystemFont,sans-serif}
.header{background:var(--card);padding:12px 24px;display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid var(--border)}
.header h1{color:var(--accent);font-size:20px;font-weight:800}
.header .badge{color:var(--text);font-size:10px;padding:2px 8px;background:rgba(30,41,59,0.8);border-radius:4px}
.header .live{color:var(--green);font-size:10px}
.kpi-row{display:flex;gap:10px;flex-wrap:wrap;padding:16px 24px}
.kpi{background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px 18px;text-align:center;flex:1;min-width:100px}
.kpi-val{font-size:20px;font-weight:700}
.kpi-lbl{color:var(--text);font-size:10px;text-transform:uppercase;margin-top:4px;letter-spacing:.5px}
.main-grid{display:grid;grid-template-columns:280px 1fr;gap:16px;padding:0 24px 40px}
.panel{background:var(--card);border:1px solid var(--border);border-radius:12px;padding:16px;margin-bottom:16px}
.panel-title{color:var(--bright);font-weight:600;font-size:13px;margin-bottom:12px}
.pill{display:inline-block;padding:6px 12px;margin:3px;border:1px solid var(--border);border-radius:8px;font-size:12px}
.pill .sym{color:var(--accent);font-weight:700;margin-right:6px}
.alert-row{padding:8px 12px;margin:4px 0;border-left:3px solid var(--accent);border-radius:4px;font-size:11px}
.alert-row b{font-size:11px}
.tabs{display:flex;gap:4px;margin-bottom:12px}
.tab{padding:6px 16px;border-radius:6px;cursor:pointer;font-size:12px;background:transparent;color:var(--text);border:1px solid transparent}
.tab.active{background:var(--card);color:var(--accent);border-color:var(--border)}
.tab-content{display:none}
.tab-content.active{display:block}
.chart{min-height:300px}
@media(max-width:900px){.main-grid{grid-template-columns:1fr}}
</style>
</head>
<body>
<div class="header">
<div style="display:flex;align-items:center;gap:12px"><h1>AlphaForge Pro</h1><span class="badge">v2.0</span></div>
<div style="display:flex;align-items:center;gap:16px">
<span class="live">● LIVE</span>
<span style="color:var(--text);font-size:12px" id="clock"></span>
</div>
</div>
<div class="kpi-row" id="kpis"></div>
<div class="main-grid">
<div>
<div class="panel"><div class="panel-title">Positions</div><div id="positions"></div></div>
<div class="panel"><div class="panel-title">Market Regime</div><div class="chart" id="regime"></div></div>
<div class="panel"><div class="panel-title">Sentiment</div><div class="chart" id="sentiment"></div></div>
<div class="panel"><div class="panel-title">Alerts</div><div id="alerts"></div></div>
</div>
<div>
<div class="tabs">
<div class="tab active" onclick="switchTab('pnl')">PnL & Drawdown</div>
<div class="tab" onclick="switchTab('risk')">Risk Metrics</div>
<div class="tab" onclick="switchTab('weights')">Portfolio Weights</div>
</div>
<div class="tab-content active" id="tab-pnl"><div class="chart" id="chart-pnl"></div></div>
<div class="tab-content" id="tab-risk"><div class="chart" id="chart-risk"></div></div>
<div class="tab-content" id="tab-weights"><div class="chart" id="chart-weights"></div></div>
</div>
</div>
<script>
// ─── Data ──────────────────────────────────────────────────────
const sharpe=1.82,sortino=2.14,maxDD=-4.3,var95=18340,calmar=4.2;
const positions={SPY:0.18,QQQ:0.15,AAPL:0.10,MSFT:0.12,GOOGL:0.08,AMZN:0.07,META:0.06,NVDA:0.14,TSLA:0.05,JPM:0.05};
const sentiment={AAPL:0.72,MSFT:0.65,NVDA:0.88,TSLA:-0.34,SPY:0.15};
const alertList=[{t:"10:23",lv:"info",ti:"Backtest Complete",tx:"Sharpe: 1.82, Max DD: -4.3%"},{t:"10:24",lv:"warn",ti:"Volatility Spike",tx:"VIX at 28.5, reducing exposure"},{t:"10:25",lv:"info",ti:"Regime Change",tx:"Switched to bull - increasing equity"}];
const ac={"info":"#38bdf8","warn":"#f59e0b","error":"#ef4444"};
// Generate returns and PnL
let rng=Math.seedrandom?(()=>{let s=42;return ()=>((s=(s*16807)%2147483647)/2147483647)})():Math.random;
let rets=[],pnl=0,pnls=[],dd=0,mx=0,dds=[];
for(let i=0;i<252;i++){
let r=0.0008+rng()*0.012-(i>100&&i<140?0.003:0);
if(i>140&&i<180)r=0.0025+rng()*0.012;
rets.push(r);pnl+=r*1e6;pnls.push(pnl);
}
let cum=1;rets.forEach(r=>{cum*=(1+r);mx=Math.max(mx,cum);dds.push(((cum-mx)/mx)*100);});
// Rolling metrics
let rollingSharpe=[],rollingVol=[];
for(let i=0;i<rets.length;i++){
if(i<21){rollingSharpe.push(sharpe);rollingVol.push(20);continue}
let w=rets.slice(i-21,i+1),m=w.reduce((a,b)=>a+b)/w.length;
let s=Math.sqrt(w.reduce((a,b)=>a+b*b,0)/w.length-m*m);
rollingSharpe.push(s>0?m/s*Math.sqrt(252):sharpe);
rollingVol.push(s*Math.sqrt(252)*100);
}
let dates=[];let d=new Date(2024,0,1);
for(let i=0;i<252;i++){dates.push(d.toISOString().slice(0,10));d.setDate(d.getDate()+1);if(d.getDay()===6)d.setDate(d.getDate()+2);if(d.getDay()===0)d.setDate(d.getDate()+1)}
// ─── KPIs ──────────────────────────────────────────────────────
document.getElementById("kpis").innerHTML=[
{v:"$"+pnls[pnls.length-1].toLocaleString("en-US",{maximumFractionDigits:0}),l:"Cumulative PnL",c:"var(--accent)"},
{v:sharpe.toFixed(2),l:"Sharpe",c:sharpe>=1?"var(--green)":"var(--yellow)"},
{v:sortino.toFixed(2),l:"Sortino",c:"var(--accent)"},
{v:maxDD.toFixed(1)+"%",l:"Max Drawdown",c:"var(--red)"},
{v:"$"+var95.toLocaleString(),l:"VaR 95%",c:"var(--yellow)"},
{v:calmar.toFixed(2),l:"Calmar",c:"var(--accent)"},
{v:"+12.1%",l:"Alpha",c:"var(--green)"},
{v:"0.95",l:"Beta",c:"var(--accent)"}
].map(k=>'<div class="kpi"><div class="kpi-val" style="color:'+k.c+'">'+k.v+'</div><div class="kpi-lbl">'+k.l+'</div></div>').join("");
// ─── Positions ─────────────────────────────────────────────────
document.getElementById("positions").innerHTML=Object.entries(positions).sort((a,b)=>b[1]-a[1]).map(([s,w])=>'<span class="pill"><span class="sym">'+s+'</span>'+(w*100).toFixed(1)+'%</span>').join("");
// ─── Alerts ────────────────────────────────────────────────────
document.getElementById("alerts").innerHTML=alertList.map(a=>'<div class="alert-row" style="border-left-color:'+ac[a.lv]+'"><b style="color:'+ac[a.lv]+'">['+a.t+'] '+a.ti+'</b> '+a.tx+'</div>').join("");
// ─── Charts ────────────────────────────────────────────────────
const lo={template:"plotly_dark",paper_bgcolor:"#0a0e17",plot_bgcolor:"#0a0e17",font:{color:"#94a3b8",size:11},showlegend:false,margin:{l:8,r:24,t:28,b:8}};
// PnL & Drawdown
Plotly.newPlot("chart-pnl",[
{type:"scatter",x:dates,y:pnls,line:{color:"#38bdf8",width:2},fill:"tozeroy",fillcolor:"rgba(56,189,248,0.08)",name:"PnL"},
{type:"scatter",x:dates,y:dds,line:{color:"#ef4444",width:1.5},fill:"tozeroy",fillcolor:"rgba(239,68,68,0.08)",name:"Drawdown %",yaxis:"y2"}
],{...lo,height:400,yaxis:{tickprefix:"$",tickformat:",.0f",title:"PnL $"},yaxis2:{ticksuffix:"%",title:"Drawdown %",overlaying:"y",side:"right"}});
// Risk
Plotly.newPlot("chart-risk",[
{type:"scatter",x:dates,y:rollingSharpe,line:{color:"#38bdf8",width:2},name:"Rolling Sharpe"},
{type:"scatter",x:dates,y:Array(dates.length).fill(sharpe),line:{color:"rgba(239,68,68,0.5)",dash:"dot",width:1},name:"Average"},
{type:"scatter",x:dates,y:rollingVol,line:{color:"#f59e0b",width:2},name:"Volatility %",yaxis:"y2"}
],{...lo,height:400,yaxis:{title:"Sharpe"},yaxis2:{title:"Vol %",ticksuffix:"%",overlaying:"y",side:"right"}});
// Weights
let wp=Object.entries(positions).sort((a,b)=>b[1]-a[1]);
Plotly.newPlot("chart-weights",[{type:"bar",x:wp.map(e=>e[0]),y:wp.map(e=>e[1]*100),marker:{color:["#38bdf8","#38bdf8","#38bdf8","#6366f1","#6366f1","#6366f1","#10b981","#10b981","#8b5cf6","#8b5cf6"]}}],{...lo,height:340,yaxis:{title:"Weight %",ticksuffix:"%"}});
// Regime
Plotly.newPlot("regime",[{type:"pie",labels:["Bull","Bear","High Vol","Neutral"],values:[0.45,0.12,0.28,0.15],hole:0.55,marker:{colors:["#10b981","#ef4444","#f59e0b","#64748b"]},textinfo:"label+percent",textfont:{color:"#e2e8f0",size:11}}],{...lo,height:240});
// Sentiment
Plotly.newPlot("sentiment",[{type:"bar",x:Object.keys(sentiment),y:Object.values(sentiment),marker:{color:Object.values(sentiment).map(v=>v>0?"#10b981":"#ef4444")}}],{...lo,height:240,yaxis:{title:"Score",range:[-1.1,1.1]}});
// ─── Tabs ──────────────────────────────────────────────────────
function switchTab(t){
document.querySelectorAll(".tab").forEach(e=>e.classList.remove("active"));
document.querySelectorAll(".tab-content").forEach(e=>e.classList.remove("active"));
event.target.classList.add("active");
document.getElementById("tab-"+t).classList.add("active");
}
// ─── Clock ─────────────────────────────────────────────────────
setInterval(()=>{document.getElementById("clock").textContent=new Date().toLocaleString();},1000);
document.getElementById("clock").textContent=new Date().toLocaleString();
</script>
</body>
</html>