const { useState, useEffect, useCallback } = React; const API = ""; const mono = "'JetBrains Mono', monospace"; const disp = "'Space Grotesk', sans-serif"; async function api(path, opts = {}) { const token = localStorage.getItem("dkinvest_token"); const headers = { "Content-Type": "application/json", ...(token ? { Authorization: `Bearer ${token}` } : {}) }; const res = await fetch(`${API}${path}`, { ...opts, headers: { ...headers, ...opts.headers } }); if (res.status === 401) { localStorage.removeItem("dkinvest_token"); window.location.reload(); } if (!res.ok) { const e = await res.json().catch(() => ({})); throw new Error(e.detail || res.statusText); } return res.json(); } const get = (p) => api(p); const post = (p, body) => api(p, { method: "POST", body: JSON.stringify(body) }); // ═══ TOOLTIP DESCRIPTIONS ════════════════════════════════════════════════════ const AGENT_TIPS = { framework_compliance: "Checks ROIC quality, capital allocation efficiency, and compliance with investment framework criteria (e.g. Greenblatt, quality/growth stock-type rules).", earnings_quality: "Piotroski F-Score (0-9), accrual ratio, cash flow vs earnings comparison, and Altman Z-score. Higher = more trustworthy earnings.", fundamental: "Valuation ratios (P/E, P/B, EV/EBITDA), profitability (ROE, margins), growth rates, and balance sheet health. Positive = undervalued.", technical: "RSI, MACD, price vs moving averages (SMA20/50/200), volume trends, and support/resistance levels. Positive = bullish momentum.", sentiment: "Analyst consensus rating (1-5 scale), target price upside, and number of covering analysts. More analysts = higher confidence.", volatility_structure: "30-day realized volatility percentile, volume profile analysis, and correlation with market index. Low vol = positive score.", peer_comparison: "Relative valuation and quality vs sector peers. Compares P/E, margins, growth, and ROIC against 5-10 comparable companies.", macro_economic: "Impact of interest rates, inflation, currency, and economic cycle on this stock's sector. Positive = macro tailwinds.", news_intelligence: "Sentiment analysis of recent news articles. Requires NewsAPI. Shows neutral (0.00) when no news is available.", annual_report: "RAG analysis of the company's annual report PDF. Requires ChromaDB and an uploaded PDF. Neutral until configured.", insider_trading: "Insider buy/sell transaction patterns. Cluster buying = very bullish. Neutral when no insider data is available.", dividend_return: "Dividend yield, payout sustainability, growth history, and coverage ratio. Zero for non-dividend stocks.", regime_detection: "Market-wide signal based on OMXC25/S&P500 trend and VIX volatility. Same score for all stocks. Positive = bull market.", macro_signal: "Macro regime overlay: rates environment, inflation momentum, liquidity conditions, and risk appetite indicators.", narrative_signal: "Exposure to active market narratives (e.g. AI, green energy, inflation). Based on news topic clustering.", market_map: "Position in the market correlation graph. Stocks in strong clusters with high centrality score higher.", }; const METRIC_TIPS = { price: "Current market price from Yahoo Finance (last trading day close).", target: "Analyst consensus target price. Average of all covering analysts' 12-month price targets.", upside: "Percentage difference between current price and analyst target. Positive = analysts expect the stock to rise.", risk: "Risk assessment: low (stable, diversified), medium (normal volatility), high (volatile, concentrated, or in drawdown).", composite_score: "Weighted average of all 19 agent scores. Range: -1 (strong sell) to +1 (strong buy). Weights are adaptive based on past accuracy.", confidence: "How certain the system is about this recommendation. Low confidence means many agents had insufficient data or disagreed.", }; // ═══ TOOLTIP COMPONENT ═══════════════════════════════════════════════════════ function Tip({ text, children }) { const [show, setShow] = useState(false); const [pos, setPos] = useState({ x: 0, y: 0 }); const handleEnter = (e) => { const rect = e.currentTarget.getBoundingClientRect(); setPos({ x: rect.left, y: rect.bottom + 4 }); setShow(true); }; return setShow(false)} style={{ cursor: "help", borderBottom: text ? "1px dotted #475569" : "none", position: "relative" }}> {children} {show && text && {text}} ; } // ═══ SHARED COMPONENTS ═══════════════════════════════════════════════════════ function ScoreBar({ value }) { const w = Math.abs(value||0)*50, pos = (value||0) >= 0; return
{pos?"+":""}{(value||0).toFixed(2)}
; } function Badge({ action }) { const c = {BUY:{bg:"#052e16",b:"#166534",t:"#22c55e"},HOLD:{bg:"#1c1917",b:"#44403c",t:"#a8a29e"},SELL:{bg:"#2d0a0a",b:"#7f1d1d",t:"#ef4444"}}[action]||{bg:"#1c1917",b:"#44403c",t:"#a8a29e"}; return {action}; } function Btn({ children, onClick, variant="default", disabled, style:s={} }) { const v = {default:{background:"#1e293b",color:"#94a3b8"},primary:{background:"#1d4ed8",color:"#e2e8f0"},danger:{background:"#7f1d1d",color:"#fca5a5"},success:{background:"#14532d",color:"#86efac"},ghost:{background:"transparent",color:"#64748b",border:"1px solid #1e293b"}}[variant]; return ; } function Loading() { return
Loading...
; } function Card({ title, tip, children, style:s={} }) { return
{title&&
{tip?{title}:title}
} {children}
; } function Metric({ label, value, color, sub, tip }) { return
{tip?{label}:label}
{value}
{sub&&
{sub}
}
; } // ═══ LOGIN ════════════════════════════════════════════════════════════════════ function LoginScreen({ onLogin }) { const [u,setU]=useState(""); const [p,setP]=useState(""); const [err,setErr]=useState(""); const [isReg,setIsReg]=useState(false); const [dn,setDn]=useState(""); const doAuth=async()=>{try{setErr(""); let data; if(isReg){data=await post("/api/auth/register",{username:u,password:p,display_name:dn||u});} else{const form=new URLSearchParams();form.append("username",u);form.append("password",p); const res=await fetch("/api/auth/login",{method:"POST",body:form});if(!res.ok)throw new Error("Invalid credentials");data=await res.json();} localStorage.setItem("dkinvest_token",data.access_token);onLogin(data.user);}catch(e){setErr(e.message);}}; const is={width:"100%",padding:8,background:"#080c14",border:"1px solid #1e293b",borderRadius:5,color:"#e2e8f0",fontSize:11,fontFamily:mono,marginBottom:8}; return

DKInvest

{isReg&&setDn(e.target.value)} placeholder="Display name" style={is}/>} setU(e.target.value)} placeholder="Username" style={is} onKeyDown={e=>e.key==="Enter"&&doAuth()}/> setP(e.target.value)} placeholder="Password" type="password" style={is} onKeyDown={e=>e.key==="Enter"&&doAuth()}/> {err&&
{err}
} {isReg?"Register":"Sign In"}
setIsReg(!isReg)} style={{fontSize:10,color:"#818cf8",cursor:"pointer"}}>{isReg?"Already have an account?":"Create account"}
; } // ═══ HOME ═════════════════════════════════════════════════════════════════════ function HomeTab({ recs }) { const buys=(recs||[]).filter(r=>r.action==="BUY").length; const sells=(recs||[]).filter(r=>r.action==="SELL").length; const holds=(recs||[]).filter(r=>r.action==="HOLD").length; const top=(recs||[]).sort((a,b)=>(b.composite_score||0)-(a.composite_score||0)).slice(0,5); return
{top.map(r=>
{r.ticker} {r.company_name}
)}
; } // ═══ STOCKS ═══════════════════════════════════════════════════════════════════ function StocksTab({ recs, onRefresh, onAddStock }) { const [expanded,setExpanded]=useState(null); const [detail,setDetail]=useState(null); const [ticker,setTicker]=useState(""); const [adding,setAdding]=useState(false); const doAdd=async()=>{if(!ticker)return; setAdding(true); try{await onAddStock({ticker:ticker.toUpperCase()});setTicker("");}catch(e){}setAdding(false);}; const loadDetail=async(t)=>{if(expanded===t){setExpanded(null);return;} setExpanded(t); setDetail(null); try{const thesis=await get(`/api/stocks/${t}/thesis`).catch(()=>null); setDetail({thesis,rec:(recs||[]).find(r=>r.ticker===t)});}catch(e){setDetail(null);}}; return
Stock Analysis
setTicker(e.target.value)} placeholder="Add ticker..." style={{width:110,padding:5,background:"#04060c",border:"1px solid #1e293b",borderRadius:4,color:"#e2e8f0",fontSize:10,fontFamily:mono}} onKeyDown={e=>e.key==="Enter"&&doAdd()}/> {adding?"Adding...":"+ Add"} Refresh
{(recs||[]).map(r=>
loadDetail(r.ticker)}>
{r.ticker} {r.company_name}
conf:{((r.confidence||0)*100).toFixed(0)}% {expanded===r.ticker?"\u25B2":"\u25BC"}
{expanded===r.ticker&&
{r.agents&&Object.keys(r.agents).length>0&&
AGENT SCORES
{Object.entries(r.agents).sort((a,b)=>Math.abs(b[1])-Math.abs(a[1])).map(([name,score])=>
=0?"+":""}${score.toFixed(2)}`}> {name.replace(/_/g," ")}
)}
}
{r.current_price&&
Price
{r.current_price?.toFixed(2)}
} {r.target_price&&
Target
{r.target_price?.toFixed(2)}
} {r.upside_pct!=null&&
Upside
0?"#22c55e":"#ef4444"}}>{(r.upside_pct||0)>0?"+":""}{r.upside_pct?.toFixed(1)}%
} {r.risk_level&&
Risk
{r.risk_level}
}
{detail?.thesis?.available&&
BULL CASE
{detail.thesis.bull_case}
BEAR CASE
{detail.thesis.bear_case}
{detail.thesis.catalysts?.length>0&&
CATALYSTS
{detail.thesis.catalysts.map((c,i)=>{c})}
} {detail.thesis.risk_factors?.length>0&&
RISKS
{detail.thesis.risk_factors.map((rf,i)=>{rf})}
}
} {r.reasoning_summary&&
REASONING
{r.reasoning_summary}
}
}
)} {(!recs||recs.length===0)&&
No recommendations yet.
}
; } // ═══ PORTFOLIO ════════════════════════════════════════════════════════════════ function PortfolioTab() { const [pf,setPf]=useState(null); const [loading,setLoading]=useState(true); const [t,setT]=useState(""); const [sh,setSh]=useState(""); const [pr,setPr]=useState(""); useEffect(()=>{(async()=>{try{setPf(await get("/api/portfolio"));}catch(e){}setLoading(false);})();},[]); const buy=async()=>{if(!t||!sh||!pr)return; await post("/api/portfolio/transaction",{ticker:t.toUpperCase(),transaction_type:"BUY",shares:+sh,price_per_share:+pr,transaction_date:new Date().toISOString().split("T")[0]});setPf(await get("/api/portfolio"));setT("");setSh("");setPr("");}; if(loading)return ; const h=pf?.holdings||[]; const tv=h.reduce((s,x)=>s+(x.current_value||0),0); const tc=h.reduce((s,x)=>s+(x.total_invested||0),0); const tp=tv-tc; return
=0?"+":""}${tp.toLocaleString(undefined,{minimumFractionDigits:0})}`} color={tp>=0?"#22c55e":"#ef4444"} sub={tc>0?`${((tp/tc)*100).toFixed(1)}%`:""} tip="Profit or loss: current value minus total amount invested."/>
{h.map(x=>
{x.ticker} {x.shares} @ {x.avg_purchase_price?.toFixed(2)}
{x.current_value?.toLocaleString()}
=0?"#22c55e":"#ef4444"}}>{(x.pnl_pct||0)>=0?"+":""}{x.pnl_pct?.toFixed(1)}%
)}
setT(e.target.value)} placeholder="Ticker" style={{flex:1,padding:6,background:"#04060c",border:"1px solid #1e293b",borderRadius:4,color:"#e2e8f0",fontSize:10,fontFamily:mono}}/> setSh(e.target.value)} placeholder="Shares" type="number" style={{width:70,padding:6,background:"#04060c",border:"1px solid #1e293b",borderRadius:4,color:"#e2e8f0",fontSize:10,fontFamily:mono}}/> setPr(e.target.value)} placeholder="Price" type="number" style={{width:80,padding:6,background:"#04060c",border:"1px solid #1e293b",borderRadius:4,color:"#e2e8f0",fontSize:10,fontFamily:mono}}/> Buy
; } // ═══ MARKET INSIGHTS ═════════════════════════════════════════════════════════ function MarketInsightsTab() { const [macro,setMacro]=useState(null); const [narr,setNarr]=useState(null); const [mmap,setMmap]=useState(null); const [loading,setLoading]=useState(true); useEffect(()=>{(async()=>{const[m,n,mm]=await Promise.all([get("/api/macro/environment").catch(()=>null),get("/api/narratives/overview").catch(()=>null),get("/api/market-map/snapshot").catch(()=>null)]); setMacro(m);setNarr(n);setMmap(mm);setLoading(false);})();},[]); if(loading)return ; const rc={inflationary_expansion:"#f97316",disinflationary_growth:"#22c55e",stagflation:"#ef4444",deflationary_recession:"#64748b"}; const mr=macro?.regime?.regime||"unknown"; return
Market Insights
{mr.replace(/_/g," ").toUpperCase()}
{macro?.regime?.strategy_hints?.description&&
{macro.regime.strategy_hints.description}
} {macro?.features&&Object.entries(macro.features).slice(0,6).map(([k,v])=>
{k.replace(/_/g," ")} 0?"#22c55e":v<0?"#ef4444":"#64748b"}}>{typeof v==="number"?v.toFixed(3):v}
)}
{(narr?.top_narratives||[]).length>0&&<>
Narratives
{narr.top_narratives.map((n,i)=>
{n.name}
Intensity
{(n.intensity||0).toFixed(2)}
Sentiment
0?"#22c55e":"#ef4444"}}>{(n.sentiment||0)>0?"+":""}{(n.sentiment||0).toFixed(2)}
)}
}
; } // ═══ ALERTS ═══════════════════════════════════════════════════════════════════ function AlertsTab() { const [alerts,setAlerts]=useState(null); const [loading,setLoading]=useState(true); useEffect(()=>{(async()=>{try{setAlerts(await get("/api/alerts?limit=50"));}catch(e){}setLoading(false);})();},[]); if(loading)return ; return
Alerts
{(alerts?.alerts||[]).map(a=>
{a.title} {new Date(a.created_at).toLocaleDateString()}
{a.message}
)} {(alerts?.alerts||[]).length===0&&
No alerts.
}
; } // ═══ DISCOVERY ════════════════════════════════════════════════════════════════ function DiscoveryTab() { const [data,setData]=useState(null); const [loading,setLoading]=useState(true); const [running,setRunning]=useState(false); useEffect(()=>{(async()=>{try{setData(await get("/api/discovery"));}catch(e){}setLoading(false);})();},[]); const runDisc=async()=>{setRunning(true);try{await post("/api/discovery/run",{});setTimeout(async()=>{try{setData(await get("/api/discovery"));}catch(e){}setRunning(false);},30000);}catch(e){setRunning(false);}}; const dismiss=async(t)=>{try{await post("/api/discovery/dismiss",{ticker:t});setData(await get("/api/discovery"));}catch(e){}}; const addWL=async(t,n)=>{try{await post("/api/watchlist/add",{ticker:t,company_name:n});setData(await get("/api/discovery"));}catch(e){}}; if(loading)return ; const report=data?.report; const cands=(report?.investigate||report?.candidates||[]); const dism=new Set(data?.dismissed_tickers||[]); const tracked=new Set(data?.tracked_tickers||[]); const vis=cands.filter(c=>!dism.has(c.ticker)&&!tracked.has(c.ticker)); return
Stock Discovery
Find new investment candidates
{running?"\u23F3 Scanning...":"\uD83D\uDD0D Run Discovery"}
{report&&
} {vis.length>0?vis.map(c=>
{c.ticker} {c.company_name||c.name||""} {c.sector&&{c.sector}}
addWL(c.ticker,c.company_name||c.name)} variant="success">+ Add dismiss(c.ticker)} variant="ghost">Dismiss
{c.reason&&
{c.reason}
}
):
{report?"All candidates tracked or dismissed.":"No discovery report. Click Run Discovery."}
}
; } // ═══ SIMULATION ═══════════════════════════════════════════════════════════════ function SimulationTab() { const [simDate,setSimDate]=useState("2024-06-01"); const [simTicker,setSimTicker]=useState("NOVO-B.CO"); const [results,setResults]=useState(null); const [history,setHistory]=useState(null); const [running,setRunning]=useState(false); const [loading,setLoading]=useState(true); useEffect(()=>{(async()=>{try{setHistory(await get("/api/simulation/results"));}catch(e){}setLoading(false);})();},[]); const runSim=async()=>{setRunning(true); try{const resp=await post("/api/simulation/run",{date:simDate,ticker:simTicker}); const jid=resp.job_id; const poll=async(n)=>{if(n<=0){setRunning(false);return;} try{const j=await get(`/api/jobs/${jid}`); if(j.status==="completed"){setResults(j.result);setHistory(await get("/api/simulation/results"));setRunning(false);} else if(j.status==="failed"){setRunning(false);} else{setTimeout(()=>poll(n-1),3000);} }catch(e){setTimeout(()=>poll(n-1),3000);}}; setTimeout(()=>poll(40),3000); }catch(e){setRunning(false);}}; return
Point-in-Time Simulation
Test what the system would have recommended on a past date and see how it performed
Date
setSimDate(e.target.value)} style={{padding:6,background:"#04060c",border:"1px solid #1e293b",borderRadius:4,color:"#e2e8f0",fontSize:10,fontFamily:mono}}/>
Ticker
setSimTicker(e.target.value)} style={{width:120,padding:6,background:"#04060c",border:"1px solid #1e293b",borderRadius:4,color:"#e2e8f0",fontSize:10,fontFamily:mono}}/>
{running?"\u23F3 Simulating...":"\u25B6 Run"}
{results?.results&& {results.results.map((r,i)=>
{r.ticker} {r.simulation_date}
Score: {r.score>=0?"+":""}{r.score?.toFixed(2)}
{r.forward_performance?.available&&
{["7d","30d","90d"].map(p=>{const v=r.forward_performance[p+"_return"]; return v!=null?
{p}
=0?"#22c55e":"#ef4444"}}>{v>=0?"+":""}{v}%
:null;})} {r.forward_performance.max_drawdown!=null&&
Max DD
{r.forward_performance.max_drawdown}%
} {r.forward_performance.correct_direction!=null&&
Correct?
{r.forward_performance.correct_direction?"\u2705":"\u274C"}
}
}
)}
} {(history?.results||[]).length>0?(history.results||[]).slice(0,10).map((r,i)=>
{r.ticker} {r.simulation_date}
{r.forward_performance?.["30d_return"]!=null&&=0?"#22c55e":"#ef4444"}}>30d: {r.forward_performance["30d_return"]>=0?"+":""}{r.forward_performance["30d_return"]}%} {r.forward_performance?.correct_direction!=null&&{r.forward_performance.correct_direction?"\u2705":"\u274C"}}
):
No simulations yet.
}
; } // ═══ RESEARCH LAB ═════════════════════════════════════════════════════════════ function ResearchLabTab() { const [ml,setMl]=useState(null); const [perf,setPerf]=useState(null); const [weights,setWeights]=useState(null); const [running,setRunning]=useState({}); useEffect(()=>{(async()=>{const[m,p,w]=await Promise.all([get("/api/ml/status").catch(()=>null),get("/api/performance").catch(()=>null),get("/api/ml/agent-weights").catch(()=>null)]);setMl(m);setPerf(p);setWeights(w);})();},[]); const run=async(id,ep)=>{setRunning(r=>({...r,[id]:true}));try{await post(ep,{});}catch(e){}setTimeout(()=>setRunning(r=>({...r,[id]:false})),3000);}; const acts=[{id:"retrain",label:"Retrain ML",endpoint:"/api/ml/retrain",icon:"\uD83E\uDDE0"},{id:"learn",label:"Learning Cycle",endpoint:"/api/ml/run-learning",icon:"\uD83D\uDCCA"},{id:"research",label:"Research Pipeline",endpoint:"/api/research/run",icon:"\uD83E\uDDEA"}, {id:"narratives",label:"Refresh Narratives",endpoint:"/api/narratives/refresh",icon:"\uD83D\uDCF0"},{id:"mmap",label:"Market Map",endpoint:"/api/market-map/refresh",icon:"\uD83D\uDDFA\uFE0F"},{id:"macro",label:"Update Macro",endpoint:"/api/macro/update",icon:"\uD83C\uDF0D"}]; return
Research Lab ADMIN
{acts.map(a=>run(a.id,a.endpoint)} variant="primary" disabled={running[a.id]} style={{padding:10,display:"flex",flexDirection:"column",alignItems:"center",gap:3}}> {a.icon}{running[a.id]?"Running...":a.label})}
{ml?.trained?"TRAINED":"NOT TRAINED"}
{perf&&perf.evaluated>0&&
Evaluated
{perf.evaluated}
BUY
{perf.buy?.hit_rate_pct?.toFixed(0)||0}%
SELL
{perf.sell?.hit_rate_pct?.toFixed(0)||0}%
}
; } // ═══ MAIN APP ═════════════════════════════════════════════════════════════════ function DKInvestApp() { const [user,setUser]=useState(null); const [tab,setTab]=useState("home"); const [recs,setRecs]=useState(null); const [loading,setLoading]=useState(true); useEffect(()=>{const t=localStorage.getItem("dkinvest_token"); if(t){get("/api/auth/me").then(u=>{setUser(u);loadRecs();}).catch(()=>{localStorage.removeItem("dkinvest_token");setLoading(false);});}else{setLoading(false);}},[]); const loadRecs=async()=>{try{const d=await get("/api/recommendations");setRecs(d.recommendations);}catch(e){}setLoading(false);}; const addStock=async(s)=>{await post("/api/watchlist/add",s);setTimeout(loadRecs,2000);}; const logout=()=>{localStorage.removeItem("dkinvest_token");setUser(null);setRecs(null);}; if(loading)return
Loading...
; if(!user)return {setUser(u);loadRecs();}}/>; const isAdmin=user.is_admin; const tabs=[{id:"home",label:"Home",icon:"\uD83C\uDFE0"},{id:"stocks",label:"Stocks",icon:"\uD83D\uDCCA"},{id:"portfolio",label:"Portfolio",icon:"\uD83D\uDCBC"}, {id:"insights",label:"Insights",icon:"\uD83C\uDF0D"},{id:"discovery",label:"Discovery",icon:"\uD83D\uDD0D"},{id:"simulation",label:"Simulation",icon:"\u23F1\uFE0F"}, {id:"alerts",label:"Alerts",icon:"\uD83D\uDD14"},...(isAdmin?[{id:"research",label:"Research",icon:"\uD83D\uDD2C"}]:[])]; return

DKInvest

v9
{user.display_name||user.username} Logout
{tabs.map(t=>)}
{tab==="home"&&} {tab==="stocks"&&} {tab==="portfolio"&&} {tab==="insights"&&} {tab==="discovery"&&} {tab==="simulation"&&} {tab==="alerts"&&} {tab==="research"&&isAdmin&&}
DKInvest v9 · 19 agents · {isAdmin?"Admin":"User"} Not financial advice
; } window.__dkinvest_app = DKInvestApp;