← back to Bertha
chore(alshi-dash): update 1 file (.js) [+209/-56]
a53e7ad258fb7032db6575240921add10608c9e8 · 2026-02-16 16:47:31 +0000 · DW Commit Agent
Files touched
Diff
commit a53e7ad258fb7032db6575240921add10608c9e8
Author: DW Commit Agent <commit-agent@dw-agents.com>
Date: Mon Feb 16 16:47:31 2026 +0000
chore(alshi-dash): update 1 file (.js) [+209/-56]
---
kalshi-dash/server.js | 265 +++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 209 insertions(+), 56 deletions(-)
diff --git a/kalshi-dash/server.js b/kalshi-dash/server.js
index 8562d71..1f77e88 100644
--- a/kalshi-dash/server.js
+++ b/kalshi-dash/server.js
@@ -2449,70 +2449,223 @@ function SignalFeed({ signals }) {
// ── PORTFOLIOS TAB ──
function PortfoliosTab() {
- const [portfolios, setPortfolios] = useState([]);
- const [trades, setTrades] = useState([]);
- const [selectedPf, setSelectedPf] = useState(null);
+ const [data, setData] = useState(null);
+ const [histFilter, setHistFilter] = useState('all');
useEffect(() => {
- api('/api/portfolios').then(setPortfolios).catch(()=>{});
- api('/api/portfolio-trades').then(setTrades).catch(()=>{});
- const iv = setInterval(() => {
- api('/api/portfolios').then(setPortfolios).catch(()=>{});
- if (selectedPf) api('/api/portfolio-trades?portfolio_id='+selectedPf).then(setTrades).catch(()=>{});
- }, 20000);
+ const load = () => api('/api/portfauxlio').then(setData).catch(e => console.error(e));
+ load();
+ const iv = setInterval(load, 15000);
return () => clearInterval(iv);
- }, [selectedPf]);
+ }, []);
+
+ const stratColors = {aggressive:'#ef4444',conservative:'#3b82f6',weather:'#06b6d4',momentum:'#f59e0b',contrarian:'#8b5cf6',ai_enhanced:'#ec4899',mc_validated:'#a855f7',scalper:'#eab308',patient:'#22c55e',random:'#64748b'};
+ const stratEmojis = {aggressive:'\\uD83D\\uDD25',conservative:'\\uD83C\\uDFDB\\uFE0F',weather:'\\u26C8\\uFE0F',momentum:'\\uD83D\\uDE80',contrarian:'\\uD83D\\uDD04',ai_enhanced:'\\uD83E\\uDDE0',mc_validated:'\\uD83C\\uDFB2',scalper:'\\u26A1',patient:'\\uD83D\\uDC22',random:'\\uD83C\\uDFB0'};
+ const stratNames = {aggressive:'Alpha',conservative:'Beta',weather:'Storm',momentum:'Momentum',contrarian:'Contrarian',ai_enhanced:'Nova',mc_validated:'Oracle',scalper:'Shark',patient:'Turtle',random:'Wildcard'};
+ const stratDesc = {aggressive:'High edge (>15%), low confidence — speculative swings',conservative:'High confidence (>70%) — quality over quantity',weather:'Weather/climate markets only',momentum:'High agreement + articles — follows the trend',contrarian:'BUY_NO only — bets against the crowd',ai_enhanced:'Gemini AI enhanced signals only',mc_validated:'Monte Carlo validated, tight spread',scalper:'Small edges (3-10%) — quantity plays',patient:'Needs everything: conf>80%, MC, 5+ articles',random:'20% random — control group for luck testing'};
- const personalities = { aggressive:'Swings big on high-edge', conservative:'Quality over quantity', weather:'Weather markets only', momentum:'Follows the trend', contrarian:'Bets against the crowd', ai_enhanced:'Gemini AI picks only', mc_validated:'Monte Carlo confirmed', scalper:'Tiny edges, high volume', patient:'Waits for perfect setup', random:'Control group (luck test)' };
- const emojis = { aggressive:'🔥', conservative:'🏛️', weather:'⛈️', momentum:'🚀', contrarian:'🔄', ai_enhanced:'🧠', mc_validated:'🎲', scalper:'⚡', patient:'🐢', random:'🎰' };
- const colors = { aggressive:'#ef4444', conservative:'#3b82f6', weather:'#06b6d4', momentum:'#f59e0b', contrarian:'#8b5cf6', ai_enhanced:'#ec4899', mc_validated:'#a855f7', scalper:'#eab308', patient:'#22c55e', random:'#64748b' };
+ if (!data) return <div style={{textAlign:'center',padding:60,color:'var(--muted)'}}>Loading portFAUXlio data...</div>;
+
+ const { portfolios, activeTrades, tradeHistory, overlaps, summary } = data;
+ const maxInvested = Math.max(...portfolios.map(p => parseInt(p.total_invested_cents) || 0), 1);
+ const filteredHistory = histFilter === 'all' ? tradeHistory : tradeHistory.filter(t => t.strategy === histFilter);
return (<div>
- <div style={{display:'grid',gridTemplateColumns:'repeat(auto-fill,minmax(280px,1fr))',gap:12,marginBottom:20}}>
- {portfolios.map(pf => {
- const c = colors[pf.strategy]||'var(--muted)';
- return (<div key={pf.id} onClick={()=>{setSelectedPf(pf.id);api('/api/portfolio-trades?portfolio_id='+pf.id).then(setTrades);}}
- style={{background:'var(--card)',border:selectedPf===pf.id?'1px solid '+c:'1px solid var(--border)',borderRadius:14,padding:16,cursor:'pointer',transition:'all .2s',position:'relative',overflow:'hidden'}}>
- <div style={{position:'absolute',top:0,left:0,right:0,height:3,background:c,opacity:.7}}/>
- <div style={{display:'flex',alignItems:'center',gap:10,marginBottom:8}}>
- <span style={{fontSize:24}}>{emojis[pf.strategy]||'📊'}</span>
- <div>
- <div style={{fontSize:15,fontWeight:700,color:c}}>{pf.name}</div>
- <div style={{fontSize:10,color:'var(--muted)',textTransform:'uppercase',letterSpacing:.5}}>{pf.strategy}</div>
+ {/* ═══ Banner ═══ */}
+ <div className="pf-banner">
+ <div className="pf-banner-title">portFAUXlio</div>
+ <div className="pf-banner-sub">10 Strategy Models • Paper Trading • Real Signals • Zero Real Money</div>
+ </div>
+
+ {/* ═══ Summary Stats ═══ */}
+ <div className="pf-summary-row">
+ <div className="pf-summary-card">
+ <div className="pf-summary-val" style={{color: summary.totalPnl >= 0 ? 'var(--green)' : 'var(--red)'}}>
+ {summary.totalPnl >= 0 ? '+' : ''}{'$'}{(summary.totalPnl / 100).toFixed(2)}
+ </div>
+ <div className="pf-summary-lbl">Total P&L</div>
+ </div>
+ <div className="pf-summary-card">
+ <div className="pf-summary-val" style={{color:'var(--blue)'}}>{'$'}{(summary.totalInvested / 100).toFixed(2)}</div>
+ <div className="pf-summary-lbl">Invested</div>
+ </div>
+ <div className="pf-summary-card">
+ <div className="pf-summary-val" style={{color:'var(--purple)'}}>{summary.totalTrades}</div>
+ <div className="pf-summary-lbl">Total Trades</div>
+ </div>
+ <div className="pf-summary-card">
+ <div className="pf-summary-val" style={{color:'var(--green)'}}>{summary.openTrades}</div>
+ <div className="pf-summary-lbl">Open Positions</div>
+ </div>
+ <div className="pf-summary-card">
+ <div className="pf-summary-val" style={{color:'var(--cyan)'}}>{summary.uniqueMarkets}</div>
+ <div className="pf-summary-lbl">Markets</div>
+ </div>
+ <div className="pf-summary-card">
+ <div className="pf-summary-val" style={{color:'var(--yellow)'}}>{summary.activeModels}/10</div>
+ <div className="pf-summary-lbl">Active Models</div>
+ </div>
+ </div>
+
+ {/* ═══ Active Trades Strip ═══ */}
+ {activeTrades.length > 0 && <div className="pf-active-strip">
+ <div className="pf-active-header">
+ <span className="dot" />
+ {activeTrades.length} Open Positions
+ </div>
+ <div className="pf-active-scroll">
+ {activeTrades.map((t, i) => {
+ const c = stratColors[t.strategy] || 'var(--muted)';
+ return (<div key={i} className="pf-active-card" style={{borderTopColor: c}}>
+ <div style={{display:'flex',alignItems:'center',gap:6,marginBottom:4}}>
+ <span style={{fontSize:14}}>{stratEmojis[t.strategy] || ''}</span>
+ <span style={{fontSize:11,fontWeight:700,color:c}}>{t.portfolio_name}</span>
+ <span style={{marginLeft:'auto',padding:'1px 6px',borderRadius:4,fontSize:9,fontWeight:700,
+ background: t.direction === 'BUY_YES' ? 'rgba(34,197,94,.15)' : 'rgba(239,68,68,.15)',
+ color: t.direction === 'BUY_YES' ? 'var(--green)' : 'var(--red)'
+ }}>{t.direction === 'BUY_YES' ? 'YES' : 'NO'}</span>
</div>
- <div style={{marginLeft:'auto',textAlign:'right'}}>
- <div style={{fontSize:18,fontWeight:700,color:pf.balance_cents>=0?'var(--green)':'var(--red)',fontVariantNumeric:'tabular-nums'}}>
- {pf.balance_cents>=0?'+':''}\${(pf.balance_cents/100).toFixed(2)}
- </div>
- <div style={{fontSize:10,color:'var(--muted)'}}>P&L</div>
+ <div style={{fontSize:10,fontWeight:600,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap',marginBottom:3}} title={t.market_title || t.market_id}>
+ {t.market_title || t.market_id}
</div>
- </div>
- <div style={{fontSize:11,color:'var(--muted)',marginBottom:8,lineHeight:1.4}}>{personalities[pf.strategy]}</div>
- <div style={{display:'flex',gap:6,flexWrap:'wrap'}}>
- <span style={{padding:'2px 8px',borderRadius:4,fontSize:10,background:'rgba(34,197,94,.12)',color:'var(--green)'}}>W:{pf.trades_won}</span>
- <span style={{padding:'2px 8px',borderRadius:4,fontSize:10,background:'rgba(239,68,68,.12)',color:'var(--red)'}}>L:{pf.trades_lost}</span>
- <span style={{padding:'2px 8px',borderRadius:4,fontSize:10,background:'rgba(255,255,255,.05)',color:'var(--muted)'}}>WR:{pf.win_rate}%</span>
- <span style={{padding:'2px 8px',borderRadius:4,fontSize:10,background:'rgba(255,255,255,.05)',color:'var(--muted)'}}>Today:{pf.trades_today}</span>
- <span style={{padding:'2px 8px',borderRadius:4,fontSize:10,background:pf.budget_remaining>0?'rgba(34,197,94,.08)':'rgba(239,68,68,.08)',color:pf.budget_remaining>0?'var(--green)':'var(--red)'}}>{'$'}{(pf.budget_remaining/100).toFixed(2)} left</span>
- {pf.streak!==0&&<span style={{padding:'2px 8px',borderRadius:4,fontSize:10,background:pf.streak>0?'rgba(34,197,94,.15)':'rgba(239,68,68,.15)',color:pf.streak>0?'var(--green)':'var(--red)'}}>{pf.streak>0?'🔥':'❄️'}{Math.abs(pf.streak)} streak</span>}
- </div>
- </div>);
- })}
+ <div style={{display:'flex',justifyContent:'space-between',fontSize:10,color:'var(--muted)'}}>
+ <span>{t.contracts}x @ {t.entry_price_cents}\\u00A2</span>
+ <span>{'$'}{(t.cost_cents / 100).toFixed(2)}</span>
+ <span>{timeAgo(t.created_at)}</span>
+ </div>
+ </div>);
+ })}
+ </div>
+ </div>}
+
+ {/* ═══ Model Leaderboard ═══ */}
+ <div style={{marginBottom:18}}>
+ <div style={{fontSize:13,fontWeight:700,textTransform:'uppercase',letterSpacing:.5,marginBottom:10,color:'var(--pink)',display:'flex',alignItems:'center',gap:8}}>
+ Model Leaderboard
+ <span style={{fontSize:9,fontWeight:400,color:'var(--muted)',textTransform:'none',letterSpacing:0}}>ranked by P&L</span>
+ </div>
+ <div className="pf-leaderboard">
+ <div className="pf-lb-header">
+ <span>#</span><span>Model</span><span>P&L</span><span>Invested</span><span>ROI</span><span>W</span><span>L</span><span>Trades</span><span>Strategy</span>
+ </div>
+ {portfolios.map((p, i) => {
+ const c = stratColors[p.strategy] || 'var(--muted)';
+ const pnl = parseInt(p.pnl_cents) || 0;
+ const invested = parseInt(p.total_invested_cents) || 0;
+ const resolved = parseInt(p.resolved_trades) || 0;
+ const roi = parseFloat(p.roi_pct) || 0;
+ const totalT = (parseInt(p.trades_won) || 0) + (parseInt(p.trades_lost) || 0) + (parseInt(p.trades_expired) || 0);
+ const openCount = activeTrades.filter(t => t.portfolio_id === p.id).length;
+ const medals = ['\\uD83E\\uDD47','\\uD83E\\uDD48','\\uD83E\\uDD49'];
+ return (<div key={p.id} className="pf-lb-row">
+ <span className="pf-lb-rank">{i < 3 ? medals[i] : (i+1)}</span>
+ <span className="pf-lb-name" style={{color:c}}>
+ <span style={{fontSize:16}}>{stratEmojis[p.strategy]||''}</span>
+ {p.name}
+ </span>
+ <span className="pf-lb-pnl" style={{color: pnl >= 0 ? 'var(--green)' : 'var(--red)'}}>
+ {pnl >= 0 ? '+' : ''}{'$'}{(pnl / 100).toFixed(2)}
+ </span>
+ <span className="pf-lb-invested">{'$'}{(invested / 100).toFixed(2)}</span>
+ <span className="pf-lb-roi" style={{
+ background: roi > 0 ? 'rgba(34,197,94,.12)' : roi < 0 ? 'rgba(239,68,68,.12)' : 'rgba(255,255,255,.04)',
+ color: roi > 0 ? 'var(--green)' : roi < 0 ? 'var(--red)' : 'var(--muted)'
+ }}>{roi > 0 ? '+' : ''}{roi}%</span>
+ <span className="pf-lb-wl" style={{color:'var(--green)'}}>{p.trades_won}</span>
+ <span className="pf-lb-wl" style={{color:'var(--red)'}}>{p.trades_lost}</span>
+ <span style={{fontVariantNumeric:'tabular-nums',color:'var(--muted)'}}>
+ {openCount > 0 ? <span>{openCount} <span style={{fontSize:8,color:'var(--green)'}}>OPEN</span></span> : <span style={{color:'var(--muted)'}}>0</span>}
+ {resolved > 0 && <span style={{marginLeft:4,fontSize:9}}>+{resolved}</span>}
+ </span>
+ <span style={{fontSize:9,color:'var(--muted)',overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}} title={stratDesc[p.strategy]}>
+ {p.strategy}
+ </span>
+ </div>);
+ })}
+ </div>
</div>
- {selectedPf && trades.length > 0 && (<div>
- <h3 style={{fontSize:14,fontWeight:600,marginBottom:10,color:'var(--muted)'}}>Recent Trades — {portfolios.find(p=>p.id===selectedPf)?.name}</h3>
+
+ {/* ═══ Overlap Analysis ═══ */}
+ {overlaps.length > 0 && <div className="pf-overlap">
+ <div className="pf-overlap-title">
+ \\u26A0\\uFE0F Strategy Overlap — Markets with 2+ models
+ </div>
<div style={{display:'flex',flexDirection:'column',gap:4}}>
- {trades.slice(0,20).map((t,i) => (<div key={i} style={{display:'flex',alignItems:'center',gap:10,padding:'8px 14px',background:'var(--card)',border:'1px solid var(--border)',borderRadius:8,fontSize:12}}>
- <span style={{padding:'2px 8px',borderRadius:4,fontWeight:700,fontSize:11,background:t.direction==='BUY_YES'?'rgba(34,197,94,.15)':'rgba(239,68,68,.15)',color:t.direction==='BUY_YES'?'var(--green)':'var(--red)',minWidth:55,textAlign:'center'}}>{t.direction==='BUY_YES'?'YES':'NO'}</span>
- <span style={{flex:1,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}}>{t.market_title||t.market_id}</span>
- <span style={{fontVariantNumeric:'tabular-nums',color:'var(--muted)'}}>{t.entry_price_cents}¢ x{t.contracts}</span>
- <span style={{fontWeight:700,fontVariantNumeric:'tabular-nums',color:t.status==='won'?'var(--green)':t.status==='lost'?'var(--red)':'var(--muted)',minWidth:50,textAlign:'right'}}>
- {t.status==='open'?'OPEN':t.pnl_cents>0?'+'+t.pnl_cents+'¢':t.pnl_cents+'¢'}
- </span>
- <span style={{fontSize:10,color:'var(--muted)',minWidth:60,textAlign:'right'}}>{new Date(t.created_at).toLocaleTimeString('en-US',{hour:'numeric',minute:'2-digit',hour12:true})}</span>
- </div>))}
+ {overlaps.slice(0, 8).map((o, i) => (
+ <div key={i} style={{display:'flex',alignItems:'center',gap:8,fontSize:10,padding:'4px 0'}}>
+ <span style={{fontWeight:700,color:'var(--yellow)',minWidth:20}}>{o.num_strategies}x</span>
+ <span style={{fontWeight:600,minWidth:180,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}}>{o.market_id}</span>
+ <span style={{color:'var(--muted)',flex:1,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}}>
+ {(o.portfolios || []).join(', ')}
+ </span>
+ <span style={{fontVariantNumeric:'tabular-nums',color:'var(--muted)'}}>{'$'}{((o.total_exposure || 0) / 100).toFixed(2)}</span>
+ </div>
+ ))}
</div>
- </div>)}
- {(!selectedPf || trades.length === 0) && <div style={{textAlign:'center',padding:30,color:'var(--muted)',fontSize:13}}>Click a portfolio to see its trades. Portfolios auto-trade every 2 minutes from approved signals.</div>}
+ </div>}
+
+ {/* ═══ Trade History ═══ */}
+ <div className="pf-history">
+ <div className="pf-history-header">
+ <span style={{fontSize:13,fontWeight:700,textTransform:'uppercase',letterSpacing:.5,color:'var(--cyan)'}}>Trade History</span>
+ <div style={{display:'flex',gap:4}}>
+ <button onClick={() => setHistFilter('all')} style={{padding:'3px 10px',borderRadius:6,border:'1px solid '+(histFilter==='all'?'var(--cyan)':'var(--border)'),background:histFilter==='all'?'rgba(6,182,212,.1)':'transparent',color:histFilter==='all'?'var(--cyan)':'var(--muted)',fontSize:10,fontWeight:600,cursor:'pointer'}}>All</button>
+ {portfolios.filter(p => parseInt(p.total_invested_cents) > 0).map(p => (
+ <button key={p.strategy} onClick={() => setHistFilter(p.strategy)} style={{padding:'3px 10px',borderRadius:6,border:'1px solid '+(histFilter===p.strategy?stratColors[p.strategy]:'var(--border)'),background:histFilter===p.strategy?stratColors[p.strategy]+'18':'transparent',color:histFilter===p.strategy?stratColors[p.strategy]:'var(--muted)',fontSize:10,fontWeight:600,cursor:'pointer'}}>
+ {stratEmojis[p.strategy] || ''} {p.name}
+ </button>
+ ))}
+ </div>
+ </div>
+ <div className="pf-history-list">
+ {filteredHistory.length === 0 && <div style={{textAlign:'center',padding:30,color:'var(--muted)',fontSize:12}}>No trades for this filter</div>}
+ {filteredHistory.slice(0, 100).map((t, i) => {
+ const c = stratColors[t.strategy] || 'var(--muted)';
+ const pnl = parseInt(t.pnl_cents) || 0;
+ return (<div key={i} className="pf-history-row">
+ <span style={{width:6,height:6,borderRadius:'50%',flexShrink:0,background:
+ t.status === 'open' ? 'var(--green)' : t.status === 'won' ? 'var(--blue)' : t.status === 'lost' ? 'var(--red)' : 'var(--muted)'
+ }} />
+ <span style={{minWidth:60,fontWeight:700,color:c,fontSize:10}}>{t.portfolio_name}</span>
+ <span style={{padding:'1px 6px',borderRadius:3,fontSize:9,fontWeight:700,
+ background: t.direction === 'BUY_YES' ? 'rgba(34,197,94,.12)' : 'rgba(239,68,68,.12)',
+ color: t.direction === 'BUY_YES' ? 'var(--green)' : 'var(--red)'
+ }}>{t.direction === 'BUY_YES' ? 'YES' : 'NO'}</span>
+ <span style={{flex:1,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap',color:'var(--text)'}} title={t.market_title || t.market_id}>
+ {t.market_title || t.market_id}
+ </span>
+ <span style={{fontVariantNumeric:'tabular-nums',color:'var(--muted)',fontSize:10}}>
+ {t.contracts}x @ {t.entry_price_cents}\\u00A2
+ </span>
+ <span style={{fontVariantNumeric:'tabular-nums',color:'var(--muted)',fontSize:10,minWidth:45,textAlign:'right'}}>
+ {'$'}{(t.cost_cents / 100).toFixed(2)}
+ </span>
+ <span style={{fontWeight:800,fontVariantNumeric:'tabular-nums',minWidth:55,textAlign:'right',fontSize:10,
+ color: t.status === 'open' ? 'var(--yellow)' : pnl >= 0 ? 'var(--green)' : 'var(--red)'
+ }}>
+ {t.status === 'open' ? 'OPEN' : (pnl >= 0 ? '+' : '') + (pnl / 100).toFixed(2)}
+ </span>
+ <span style={{fontSize:9,color:'var(--muted)',minWidth:55,textAlign:'right'}}>{timeAgo(t.created_at)}</span>
+ </div>);
+ })}
+ </div>
+ </div>
+
+ {/* ═══ Strategy Guide ═══ */}
+ <div style={{marginTop:18,padding:16,background:'var(--card)',border:'1px solid var(--border)',borderRadius:14}}>
+ <div style={{fontSize:11,fontWeight:700,color:'var(--muted)',textTransform:'uppercase',letterSpacing:.5,marginBottom:10}}>Strategy Guide</div>
+ <div style={{display:'grid',gridTemplateColumns:'repeat(auto-fill,minmax(280px,1fr))',gap:6}}>
+ {Object.entries(stratDesc).map(([strat, desc]) => (
+ <div key={strat} style={{display:'flex',alignItems:'flex-start',gap:8,fontSize:10,padding:'4px 0',color:'var(--muted)'}}>
+ <span style={{fontSize:14,flexShrink:0}}>{stratEmojis[strat]||''}</span>
+ <div>
+ <span style={{fontWeight:700,color:stratColors[strat]}}>{stratNames[strat]}</span>
+ <span style={{margin:'0 4px'}}>\\u2014</span>
+ {desc}
+ </div>
+ </div>
+ ))}
+ </div>
+ </div>
</div>);
}
@@ -2987,7 +3140,7 @@ function App() {
return () => clearInterval(iv);
}, []);
- if (loading) return (
+ if (loading || !data) return (
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100vh', flexDirection: 'column', gap: 16 }}>
<div style={{ width: 60, height: 60, borderRadius: '50%', background: 'linear-gradient(135deg,#ff69b4,#8b5cf6)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 28, animation: 'avatarFloat 2s ease-in-out infinite' }}>K</div>
<div style={{ color: 'var(--muted)', fontSize: 14, letterSpacing: 2 }}>INITIALIZING KEN INC...</div>
@@ -3020,7 +3173,7 @@ function App() {
<div style={{display:'flex',justifyContent:'center',gap:8,marginBottom:24,flexWrap:'wrap'}}>
<button style={tabStyle('command')} onClick={()=>setTab('command')}>Command Center</button>
<button style={tabStyle('market')} onClick={()=>setTab('market')}>Market Data</button>
- <button style={tabStyle('portfolios')} onClick={()=>setTab('portfolios')}>Portfolios (10)</button>
+ <button style={tabStyle('portfolios')} onClick={()=>setTab('portfolios')}>portFAUXlio</button>
<button style={tabStyle('predictions')} onClick={()=>setTab('predictions')}>Predictions</button>
<button style={tabStyle('signals')} onClick={()=>setTab('signals')}>Live Signals</button>
</div>
← eb35535 chore(alshi-dash): update 1 file (.js) [+209/-20]
·
back to Bertha
·
chore(alshi-dash): update 1 file (.js) [+118/-6] 2875eb9 →