Jonathan 59f833d7fd Fix candle chart staleness and show live price on today's candle
- Refresh candles on every /candles request instead of only at startup
- Patch today's candle close/high/low with the live BTC price intraday
- Synthesise today's candle from live price if CoinGecko hasn't published it yet
- Display current BTC price next to the chart title

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 19:55:01 +02:00
2026-03-24 19:10:20 +01:00

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

git clone <repo-url>
cd btc-portfolio
docker-compose up

Local Development

Backend

cd btc-portfolio/backend
pip install -r requirements.txt
uvicorn app.main:app --reload

Frontend

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.
S
Description
A portfolio of your BTC purchases, showing multiple stats and graphs
Readme 181 KiB
Languages
JavaScript 65.4%
Python 33.4%
Dockerfile 0.7%
HTML 0.5%