From d90ac5365a4a675b6fd629a32aa84cf840506bdc Mon Sep 17 00:00:00 2001 From: Jonathan Date: Mon, 6 Apr 2026 20:32:25 +0200 Subject: [PATCH] Add price prediction feature to dashboard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enter a hypothetical BTC price to instantly see predicted portfolio value, predicted P&L, and difference vs current value — all calculated client-side. Co-Authored-By: Claude Sonnet 4.6 --- btc-portfolio/frontend/src/pages/Dashboard.js | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/btc-portfolio/frontend/src/pages/Dashboard.js b/btc-portfolio/frontend/src/pages/Dashboard.js index e38f51d..f545bfc 100644 --- a/btc-portfolio/frontend/src/pages/Dashboard.js +++ b/btc-portfolio/frontend/src/pages/Dashboard.js @@ -17,6 +17,13 @@ const styles = { adminBtn: { background: 'none', border: '1px solid #f7931a', color: '#f7931a', borderRadius: '8px', padding: '0.4rem 1rem', cursor: 'pointer', textDecoration: 'none', fontSize: '1rem' }, headerBtns: { display: 'flex', gap: '0.5rem', alignItems: 'center' }, statsGrid: { display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '1rem', marginBottom: '1.5rem' }, + predictionSection: { background: '#1a1a1a', border: '1px solid #333', borderRadius: '12px', padding: '1rem', marginBottom: '1.5rem' }, + predictionHeader: { color: '#888', fontSize: '0.8rem', marginBottom: '0.75rem' }, + predictionRow: { display: 'flex', gap: '1rem', alignItems: 'flex-start', flexWrap: 'wrap' }, + predictionInputWrap: { display: 'flex', flexDirection: 'column', gap: '0.3rem' }, + predictionLabel: { color: '#888', fontSize: '0.8rem' }, + predictionInput: { background: '#111', border: '1px solid #444', borderRadius: '8px', color: '#fff', padding: '0.55rem 0.75rem', fontSize: '1rem', width: '160px', outline: 'none' }, + predictionCards: { display: 'flex', gap: '1rem', flex: 1, flexWrap: 'wrap' }, statCard: { background: '#1a1a1a', padding: '1rem', borderRadius: '12px', border: '1px solid #333' }, statLabel: { color: '#888', fontSize: '0.8rem', marginBottom: '0.3rem' }, statValue: { fontSize: '1.2rem', fontWeight: 700 }, @@ -53,6 +60,7 @@ export default function Dashboard() { const [candlesAll, setCandlesAll] = useState(null); const [fullscreenChart, setFullscreenChart] = useState(false); const [chartView, setChartView] = useState('both'); // 'both' | 'portfolio' | 'history' + const [predictionPrice, setPredictionPrice] = useState(''); const navigate = useNavigate(); const authHeaders = () => ({ @@ -107,6 +115,12 @@ export default function Dashboard() { setFullscreenChart(f => !f); }, [fullscreenChart, candlesAll, fetchAllCandles]); + const predPrice = parseFloat(predictionPrice); + const predValid = stats && predictionPrice !== '' && predPrice > 0; + const predValue = predValid ? +(stats.total_btc * predPrice).toFixed(2) : null; + const predPL = predValid ? +(predValue - stats.total_invested).toFixed(2) : null; + const predVsCurrent = predValid ? +(predValue - stats.portfolio_value).toFixed(2) : null; + const plHighlight = stats ? stats.profit_loss >= 0 ? 'positive' : 'negative' : 'neutral'; @@ -143,6 +157,42 @@ export default function Dashboard() { )} +
+
Price Prediction
+
+
+ + setPredictionPrice(e.target.value)} + style={styles.predictionInput} + /> +
+ {predValid && ( +
+ + = 0 ? '+' : ''}€${predPL.toLocaleString()}`} + highlight={predPL >= 0 ? 'positive' : 'negative'} + /> + = 0 ? '+' : ''}€${predVsCurrent.toLocaleString()}`} + highlight={predVsCurrent >= 0 ? 'positive' : 'negative'} + /> +
+ )} +
+
+
{[['both', 'Both'], ['portfolio', 'Portfolio'], ['history', 'BTC Candles']].map(([key, label]) => (