# BTC Portfolio Tracker A full-stack Bitcoin portfolio tracker with live EUR pricing, purchase/sell history, candlestick charts, and price predictions. --- ## Features - **Live BTC price** — fetched from CoinGecko in EUR, with cached fallback and stale warning - **Purchase tracking** — log BTC buys with amount (EUR), price per BTC, and a custom date - **Sell tracking** — log BTC sells with BTC amount, price per BTC, and a custom date - **Portfolio stats** — total invested, current value, profit/loss, net BTC held - **Price prediction** — enter a target BTC price to see projected portfolio value and P&L - **Interactive charts** — portfolio value over time and BTC candlestick chart (OHLC stored locally) - **Edit & delete** — inline editing and deletion for both purchases and sells - **Admin panel** — admin users can create, list, and delete accounts - **JWT authentication** — secure per-user portfolios --- ## Tech Stack | Layer | Technology | |----------|-----------------------------------------| | Frontend | React 18, Chart.js, dark theme | | Backend | FastAPI, SQLAlchemy, SQLite | | Auth | JWT (HS256, 24h expiry) + bcrypt | | Pricing | CoinGecko API (EUR) | | Deploy | Docker + Docker Compose + nginx | --- ## Getting Started ### Docker (recommended) ```bash git clone cd btc-portfolio docker-compose up ``` - Frontend: [http://localhost:3000](http://localhost:3000) - Backend API: [http://localhost:8000](http://localhost:8000) ### Local Development **Backend** ```bash cd btc-portfolio/backend pip install -r requirements.txt uvicorn app.main:app --reload ``` **Frontend** ```bash cd btc-portfolio/frontend npm install npm start ``` --- ## Project Structure ``` btc-portfolio/ ├── backend/ │ └── app/ │ ├── main.py # FastAPI app + CORS │ ├── models.py # User, Purchase, Sell, OHLCCandle ORM models │ ├── auth.py # JWT + bcrypt │ ├── dependencies.py # Auth dependency injection │ ├── routes/ │ │ ├── users.py # POST /register, POST /login │ │ ├── purchases.py # CRUD /purchases │ │ ├── sells.py # CRUD /sells │ │ ├── stats.py # GET /stats │ │ ├── history.py # GET /history (365-day BTC prices) │ │ ├── candles.py # GET /candles (OHLC data + purchases overlay) │ │ └── admin.py # GET/POST/DELETE /admin/users │ └── services/ │ └── btc.py # CoinGecko integration └── frontend/ └── src/ ├── App.js # Routing ├── pages/ │ └── Dashboard.js # Main view: stats, predictions, charts, tables └── components/ ├── AddPurchase.js # Purchase form (amount EUR, price, date) ├── PurchaseList.js # Purchase table (inline edit/delete) ├── AddSell.js # Sell form (BTC amount, price, date) ├── SellList.js # Sell table (inline edit/delete) ├── PortfolioChart.js # Invested vs current value over time └── BTCCandlestickChart.js # OHLC candlestick chart with purchase markers ``` --- ## API Endpoints | Method | Endpoint | Description | Auth | |--------|------------------------|------------------------------------|-------| | POST | `/register` | Create account | No | | POST | `/login` | Get JWT token | No | | GET | `/purchases` | List user purchases | Yes | | POST | `/purchases` | Add a purchase | Yes | | PUT | `/purchases/{id}` | Edit a purchase | Yes | | DELETE | `/purchases/{id}` | Delete a purchase | Yes | | GET | `/sells` | List user sells | Yes | | POST | `/sells` | Add a sell | Yes | | PUT | `/sells/{sell_id}` | Edit a sell | Yes | | DELETE | `/sells/{sell_id}` | Delete a sell | Yes | | GET | `/stats` | Portfolio stats (P&L, net BTC) | Yes | | GET | `/history` | 365-day BTC price history | Yes | | GET | `/candles` | OHLC candles + purchase overlay | Yes | | GET | `/admin/users` | List all users (admin only) | Admin | | POST | `/admin/users` | Create a user (admin only) | Admin | | DELETE | `/admin/users/{id}` | Delete a user (admin only) | Admin | --- ## Database SQLite, stored at `/app/data/btc_portfolio.db` (persisted via Docker volume). | Table | Columns | |----------------|---------------------------------------------------------------| | `users` | id, username (unique), password (bcrypt hash), is_admin | | `purchases` | id, amount_eur, price_eur, created_at, user_id (FK) | | `sells` | id, btc_amount, price_eur, created_at, user_id (FK) | | `ohlc_candles` | id, date (unique, YYYY-MM-DD), open, high, low, close | --- ## Notes - The `SECRET_KEY` in `auth.py` is hardcoded — use an environment variable in production. - CoinGecko requests are unauthenticated; failures fall back to the last cached price with a UI warning. - OHLC candle data is fetched from CoinGecko and stored locally to reduce API calls. - CORS is restricted to `localhost:3000` by default. - The frontend is served via nginx in the Docker production setup.