Spaces:
No application file
No application file
Upload index.html
Browse files- index.html +154 -0
index.html
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
| 6 |
+
<title>AlphaForge Pro</title>
|
| 7 |
+
<script src="https://cdn.plot.ly/plotly-2.35.2.min.js"></script>
|
| 8 |
+
<style>
|
| 9 |
+
:root{--bg:#0a0e17;--card:#111827;--accent:#38bdf8;--green:#10b981;--red:#ef4444;--yellow:#f59e0b;--text:#94a3b8;--bright:#e2e8f0;--border:#1e293b}
|
| 10 |
+
*{margin:0;padding:0;box-sizing:border-box}
|
| 11 |
+
body{background:var(--bg);color:var(--text);font-family:-apple-system,BlinkMacSystemFont,sans-serif}
|
| 12 |
+
.header{background:var(--card);padding:12px 24px;display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid var(--border)}
|
| 13 |
+
.header h1{color:var(--accent);font-size:20px;font-weight:800}
|
| 14 |
+
.header .badge{color:var(--text);font-size:10px;padding:2px 8px;background:rgba(30,41,59,0.8);border-radius:4px}
|
| 15 |
+
.header .live{color:var(--green);font-size:10px}
|
| 16 |
+
.kpi-row{display:flex;gap:10px;flex-wrap:wrap;padding:16px 24px}
|
| 17 |
+
.kpi{background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px 18px;text-align:center;flex:1;min-width:100px}
|
| 18 |
+
.kpi-val{font-size:20px;font-weight:700}
|
| 19 |
+
.kpi-lbl{color:var(--text);font-size:10px;text-transform:uppercase;margin-top:4px;letter-spacing:.5px}
|
| 20 |
+
.main-grid{display:grid;grid-template-columns:280px 1fr;gap:16px;padding:0 24px 40px}
|
| 21 |
+
.panel{background:var(--card);border:1px solid var(--border);border-radius:12px;padding:16px;margin-bottom:16px}
|
| 22 |
+
.panel-title{color:var(--bright);font-weight:600;font-size:13px;margin-bottom:12px}
|
| 23 |
+
.pill{display:inline-block;padding:6px 12px;margin:3px;border:1px solid var(--border);border-radius:8px;font-size:12px}
|
| 24 |
+
.pill .sym{color:var(--accent);font-weight:700;margin-right:6px}
|
| 25 |
+
.alert-row{padding:8px 12px;margin:4px 0;border-left:3px solid var(--accent);border-radius:4px;font-size:11px}
|
| 26 |
+
.alert-row b{font-size:11px}
|
| 27 |
+
.tabs{display:flex;gap:4px;margin-bottom:12px}
|
| 28 |
+
.tab{padding:6px 16px;border-radius:6px;cursor:pointer;font-size:12px;background:transparent;color:var(--text);border:1px solid transparent}
|
| 29 |
+
.tab.active{background:var(--card);color:var(--accent);border-color:var(--border)}
|
| 30 |
+
.tab-content{display:none}
|
| 31 |
+
.tab-content.active{display:block}
|
| 32 |
+
.chart{min-height:300px}
|
| 33 |
+
@media(max-width:900px){.main-grid{grid-template-columns:1fr}}
|
| 34 |
+
</style>
|
| 35 |
+
</head>
|
| 36 |
+
<body>
|
| 37 |
+
<div class="header">
|
| 38 |
+
<div style="display:flex;align-items:center;gap:12px"><h1>AlphaForge Pro</h1><span class="badge">v2.0</span></div>
|
| 39 |
+
<div style="display:flex;align-items:center;gap:16px">
|
| 40 |
+
<span class="live">β LIVE</span>
|
| 41 |
+
<span style="color:var(--text);font-size:12px" id="clock"></span>
|
| 42 |
+
</div>
|
| 43 |
+
</div>
|
| 44 |
+
|
| 45 |
+
<div class="kpi-row" id="kpis"></div>
|
| 46 |
+
|
| 47 |
+
<div class="main-grid">
|
| 48 |
+
<div>
|
| 49 |
+
<div class="panel"><div class="panel-title">Positions</div><div id="positions"></div></div>
|
| 50 |
+
<div class="panel"><div class="panel-title">Market Regime</div><div class="chart" id="regime"></div></div>
|
| 51 |
+
<div class="panel"><div class="panel-title">Sentiment</div><div class="chart" id="sentiment"></div></div>
|
| 52 |
+
<div class="panel"><div class="panel-title">Alerts</div><div id="alerts"></div></div>
|
| 53 |
+
</div>
|
| 54 |
+
<div>
|
| 55 |
+
<div class="tabs">
|
| 56 |
+
<div class="tab active" onclick="switchTab('pnl')">PnL & Drawdown</div>
|
| 57 |
+
<div class="tab" onclick="switchTab('risk')">Risk Metrics</div>
|
| 58 |
+
<div class="tab" onclick="switchTab('weights')">Portfolio Weights</div>
|
| 59 |
+
</div>
|
| 60 |
+
<div class="tab-content active" id="tab-pnl"><div class="chart" id="chart-pnl"></div></div>
|
| 61 |
+
<div class="tab-content" id="tab-risk"><div class="chart" id="chart-risk"></div></div>
|
| 62 |
+
<div class="tab-content" id="tab-weights"><div class="chart" id="chart-weights"></div></div>
|
| 63 |
+
</div>
|
| 64 |
+
</div>
|
| 65 |
+
|
| 66 |
+
<script>
|
| 67 |
+
// βββ Data ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 68 |
+
const sharpe=1.82,sortino=2.14,maxDD=-4.3,var95=18340,calmar=4.2;
|
| 69 |
+
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};
|
| 70 |
+
const sentiment={AAPL:0.72,MSFT:0.65,NVDA:0.88,TSLA:-0.34,SPY:0.15};
|
| 71 |
+
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"}];
|
| 72 |
+
const ac={"info":"#38bdf8","warn":"#f59e0b","error":"#ef4444"};
|
| 73 |
+
|
| 74 |
+
// Generate returns and PnL
|
| 75 |
+
let rng=Math.seedrandom?(()=>{let s=42;return ()=>((s=(s*16807)%2147483647)/2147483647)})():Math.random;
|
| 76 |
+
let rets=[],pnl=0,pnls=[],dd=0,mx=0,dds=[];
|
| 77 |
+
for(let i=0;i<252;i++){
|
| 78 |
+
let r=0.0008+rng()*0.012-(i>100&&i<140?0.003:0);
|
| 79 |
+
if(i>140&&i<180)r=0.0025+rng()*0.012;
|
| 80 |
+
rets.push(r);pnl+=r*1e6;pnls.push(pnl);
|
| 81 |
+
}
|
| 82 |
+
let cum=1;rets.forEach(r=>{cum*=(1+r);mx=Math.max(mx,cum);dds.push(((cum-mx)/mx)*100);});
|
| 83 |
+
|
| 84 |
+
// Rolling metrics
|
| 85 |
+
let rollingSharpe=[],rollingVol=[];
|
| 86 |
+
for(let i=0;i<rets.length;i++){
|
| 87 |
+
if(i<21){rollingSharpe.push(sharpe);rollingVol.push(20);continue}
|
| 88 |
+
let w=rets.slice(i-21,i+1),m=w.reduce((a,b)=>a+b)/w.length;
|
| 89 |
+
let s=Math.sqrt(w.reduce((a,b)=>a+b*b,0)/w.length-m*m);
|
| 90 |
+
rollingSharpe.push(s>0?m/s*Math.sqrt(252):sharpe);
|
| 91 |
+
rollingVol.push(s*Math.sqrt(252)*100);
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
let dates=[];let d=new Date(2024,0,1);
|
| 95 |
+
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)}
|
| 96 |
+
|
| 97 |
+
// βββ KPIs ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 98 |
+
document.getElementById("kpis").innerHTML=[
|
| 99 |
+
{v:"$"+pnls[pnls.length-1].toLocaleString("en-US",{maximumFractionDigits:0}),l:"Cumulative PnL",c:"var(--accent)"},
|
| 100 |
+
{v:sharpe.toFixed(2),l:"Sharpe",c:sharpe>=1?"var(--green)":"var(--yellow)"},
|
| 101 |
+
{v:sortino.toFixed(2),l:"Sortino",c:"var(--accent)"},
|
| 102 |
+
{v:maxDD.toFixed(1)+"%",l:"Max Drawdown",c:"var(--red)"},
|
| 103 |
+
{v:"$"+var95.toLocaleString(),l:"VaR 95%",c:"var(--yellow)"},
|
| 104 |
+
{v:calmar.toFixed(2),l:"Calmar",c:"var(--accent)"},
|
| 105 |
+
{v:"+12.1%",l:"Alpha",c:"var(--green)"},
|
| 106 |
+
{v:"0.95",l:"Beta",c:"var(--accent)"}
|
| 107 |
+
].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("");
|
| 108 |
+
|
| 109 |
+
// βββ Positions βββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 110 |
+
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("");
|
| 111 |
+
|
| 112 |
+
// βββ Alerts ββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 113 |
+
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("");
|
| 114 |
+
|
| 115 |
+
// βββ Charts ββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 116 |
+
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}};
|
| 117 |
+
|
| 118 |
+
// PnL & Drawdown
|
| 119 |
+
Plotly.newPlot("chart-pnl",[
|
| 120 |
+
{type:"scatter",x:dates,y:pnls,line:{color:"#38bdf8",width:2},fill:"tozeroy",fillcolor:"rgba(56,189,248,0.08)",name:"PnL"},
|
| 121 |
+
{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"}
|
| 122 |
+
],{...lo,height:400,yaxis:{tickprefix:"$",tickformat:",.0f",title:"PnL $"},yaxis2:{ticksuffix:"%",title:"Drawdown %",overlaying:"y",side:"right"}});
|
| 123 |
+
|
| 124 |
+
// Risk
|
| 125 |
+
Plotly.newPlot("chart-risk",[
|
| 126 |
+
{type:"scatter",x:dates,y:rollingSharpe,line:{color:"#38bdf8",width:2},name:"Rolling Sharpe"},
|
| 127 |
+
{type:"scatter",x:dates,y:Array(dates.length).fill(sharpe),line:{color:"rgba(239,68,68,0.5)",dash:"dot",width:1},name:"Average"},
|
| 128 |
+
{type:"scatter",x:dates,y:rollingVol,line:{color:"#f59e0b",width:2},name:"Volatility %",yaxis:"y2"}
|
| 129 |
+
],{...lo,height:400,yaxis:{title:"Sharpe"},yaxis2:{title:"Vol %",ticksuffix:"%",overlaying:"y",side:"right"}});
|
| 130 |
+
|
| 131 |
+
// Weights
|
| 132 |
+
let wp=Object.entries(positions).sort((a,b)=>b[1]-a[1]);
|
| 133 |
+
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:"%"}});
|
| 134 |
+
|
| 135 |
+
// Regime
|
| 136 |
+
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});
|
| 137 |
+
|
| 138 |
+
// Sentiment
|
| 139 |
+
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]}});
|
| 140 |
+
|
| 141 |
+
// βββ Tabs ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 142 |
+
function switchTab(t){
|
| 143 |
+
document.querySelectorAll(".tab").forEach(e=>e.classList.remove("active"));
|
| 144 |
+
document.querySelectorAll(".tab-content").forEach(e=>e.classList.remove("active"));
|
| 145 |
+
event.target.classList.add("active");
|
| 146 |
+
document.getElementById("tab-"+t).classList.add("active");
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
// βββ Clock βββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 150 |
+
setInterval(()=>{document.getElementById("clock").textContent=new Date().toLocaleString();},1000);
|
| 151 |
+
document.getElementById("clock").textContent=new Date().toLocaleString();
|
| 152 |
+
</script>
|
| 153 |
+
</body>
|
| 154 |
+
</html>
|