Dashboard

+ total.toFixed(2); }, runBacktest() { const btn = document.querySelector('button[onclick="app.runBacktest()"]'); if (!btn) return; const originalText = btn.innerHTML; btn.innerHTML = ` Running...`; btn.disabled = true; feather.replace(); setTimeout(() => { const resultsEl = document.getElementById('backtest-results'); const emptyEl = document.getElementById('backtest-empty'); if (resultsEl) resultsEl.classList.remove('hidden'); if (emptyEl) emptyEl.classList.add('hidden'); btn.innerHTML = originalText; btn.disabled = false; this.showToast('Backtest Completed', 'success'); }, 1500); }, // --- View Renderers --- views: { dashboard(container) { const lastRun = store.data.lastRun ? new Date(store.data.lastRun).toLocaleTimeString() : 'Never'; const hasData = store.data.sentiment.length > 0; container.innerHTML = `

Last Run

${lastRun}

${hasData ? 'Data Fresh' : 'Stale / Run Pipeline'}

Top Trending

${hasData ? store.data.sentiment.slice(0,3).map(c => `
${c.symbol} ${c.score}
`).join('') : '

No Data

'}

Active Setups

${store.data.setups.length}

Generated today

Run Daily Pipeline

Update all data

System Status

WebSocket

Connected

Database

Postgres: Healthy

Engine

Idle
`; }, sentiment(container) { const data = store.data.sentiment; if (!data.length) { container.innerHTML = `

No sentiment data. Run the pipeline first.

`; return; } const listHtml = data.map((item, idx) => `
#${idx + 1}

${item.symbol}

${item.reasons.map(r => `${r}`).join('')}

Trend Score

${item.score}/100

Conf.

${(item.confidence * 100).toFixed(0)}%

`).join(''); container.innerHTML = `

Top 5 Trending Assets based on Social, News, and On-chain volume.

${listHtml}
`; }, technicals(container) { const symbols = store.data.sentiment.map(s => s.symbol); if (symbols.length === 0) { container.innerHTML = `
Run pipeline to load technicals.
`; return; } // Generate mock data on fly if not in store for specific symbols const activeSymbol = symbols[0]; // Just show first one for demo simplicity container.innerHTML = `
${symbols.map((s, i) => ` `).join('')}
${this.renderIndicatorCard('RSI (14)', '62.4', 'Neutral', 'text-gray-400', 'line-chart')} ${this.renderIndicatorCard('MACD', '1.25', 'Bullish', 'text-green-400', 'bar-chart-2')} ${this.renderIndicatorCard('EMA (20)', '42,100', 'Above Price', 'text-rose-400', 'arrow-up')} ${this.renderIndicatorCard('ATR (14)', '450', 'Volatility High', 'text-orange-400', 'activity')} ${this.renderIndicatorCard('Bollinger', 'Upper', 'Testing Res', 'text-rose-400', 'maximize-2')} ${this.renderIndicatorCard('VWAP', '41,800', 'Support', 'text-green-400', 'target')}

Visual Chart Placeholder

Data ready for rendering library (TradingView/Recharts)

`; }, renderIndicatorCard(title, value, status, colorClass, icon) { return `

${title}

${value}
${status}
`; }, setups(container) { const setups = store.data.setups; if(setups.length === 0) { container.innerHTML = `

No active setups. Run the pipeline.

`; return; } const cards = setups.map(coin => `
${coin.symbol.substring(0,1)}

${coin.symbol} / USDT

Trend Score: ${coin.trend_score}

${coin.setups.map(s => `
${s.type.toUpperCase()} R:R ${s.rr}

Entry

$${s.entry}

Stop

$${s.stop}

Target

$${s.tp}

`).join('')}

Confluence

${coin.indicators.map(i => `${i}`).join('')}
`).join(''); container.innerHTML = `
${cards}
`; }, risk(container) { const balance = store.settings.accountBalance; const riskPct = store.settings.maxRiskPct; const riskCash = balance * riskPct; container.innerHTML = `

Position Size Calculator

Max Risk Cash

$${riskCash.toFixed(2)}

Stop Distance -
Position Size (Units) 0.00
Position Size (USD) -$0.00

Risk Constraints

Pip Equiv ≤ 50
Max Loss 2%
Slippage: 10bps
`; }, execution(container) { container.innerHTML = `

Paper Trading

Account Info

Balance $${store.settings.accountBalance.toFixed(2)}
Equity $${(store.settings.accountBalance * 1.05).toFixed(2)}

Open Positions

Paper Mode
${store.positions.length === 0 ? ` ` : store.positions.map(p => ` `).join('')}
Symbol Side Size Entry Mark PnL Action
No open positions. Place an order to start.
${p.symbol} LONG ${p.size} ${p.entry} ${(p.entry * 1.02).toFixed(2)} +$${(p.size * 2).toFixed(2)}
`; }, placeOrder(e) { e.preventDefault(); const id = Date.now().toString(); store.positions.push({ id, symbol: 'BTC/USDT', side: 'LONG', size: '0.05', entry: '42,150.00', ts: new Date() }); app.showToast('Paper Order Placed Successfully', 'success'); app.addLog('Execution', `Order placed: BTC/USDT LONG`, 'info'); this.execution(document.getElementById('content-area')); feather.replace(); }, closeOrder(id) { store.positions = store.positions.filter(p => p.id !== id); app.showToast('Position Closed', 'info'); this.execution(document.getElementById('content-area')); feather.replace(); }, backtest(container) { container.innerHTML = `

Backtest Engine

Re-run strategy on historical data.

Select a timeframe and click Run to view results.

`; }, logs(container) { const logs = store.logs; container.innerHTML = `

System Logs

${logs.length === 0 ? '

No logs yet.

' : logs.map(l => `
${l.timestamp.split('T')[1].split('.')[0]} [${l.source}] ${l.message}
`).join('')}
`; }, settings(container) { container.innerHTML = `

Risk Parameters

API Keys (Server-side)

Stored securely in backend env vars.

`; } }, calculateRisk() { const entry = parseFloat(document.getElementById('risk-entry').value); const stop = parseFloat(document.getElementById('risk-stop').value); if (!entry || !stop || entry === stop) { app.showToast('Invalid Entry/Stop prices', 'error'); return; } const dist = Math.abs(entry - stop); const riskCash = store.settings.accountBalance * store.settings.maxRiskPct; const units = riskCash / dist; const total = units * entry; document.getElementById('res-dist').innerText = dist.toFixed(2); document.getElementById('res-units').innerText = units.toFixed(4); document.getElementById('res-total').innerText = '$' + total.toFixed(2); }, runBacktest() { const btn = document.querySelector('button[onclick="app.runBacktest()"]'); const originalText = btn.innerHTML; btn.innerHTML = ` Running...`; feather.replace(); setTimeout(() => { document.getElementById('backtest-results').classList.remove('hidden'); document.getElementById('backtest-empty').classList.add('hidden'); btn.innerHTML = originalText; app.showToast('Backtest Completed', 'success'); }, 1500); } }; // Start the app app.init();