Build a Free Crypto Portfolio Tracker Agent in 30 Minutes
Most portfolio trackers are web apps that require an account, track your data, and eventually upsell you. You don't need any of that. With Python and a few free APIs, you can build a portfolio tracker that runs on your machine, stores everything locally, and costs nothing to operate.
Let's build it.
What You'll Build
- A portfolio tracker that fetches real-time prices
- P&L calculation for each holding
- A daily summary emailed or printed to terminal
- Data stored locally (SQLite or JSON)
- Optional: Telegram alerts when portfolio moves ±5%
Time to build: ~30 minutes
Cost: Free
External services: None required
Step 1: Define Your Portfolio
Start simple — a JSON file with your holdings:
{
"holdings": [
{"symbol": "BTC", "amount": 0.05, "avg_buy_price": 30000},
{"symbol": "ETH", "amount": 1.5, "avg_buy_price": 1800},
{"symbol": "SOL", "amount": 20, "avg_buy_price": 85},
{"symbol": "BNB", "amount": 3, "avg_buy_price": 250}
]
}
Save as portfolio.json. You'll update this when you buy/sell.
Step 2: Fetch Real-Time Prices
Binance offers a completely free, no-auth-required price API:
import requests
def get_prices(symbols: list) -> dict:
"""Fetch current prices for a list of symbols."""
prices = {}
for symbol in symbols:
ticker = f"{symbol}USDT"
url = f"https://api.binance.com/api/v3/ticker/price?symbol={ticker}"
try:
r = requests.get(url, timeout=5)
prices[symbol] = float(r.json()["price"])
except Exception as e:
print(f"Error fetching {symbol}: {e}")
prices[symbol] = None
return prices
Test it:
prices = get_prices(["BTC", "ETH", "SOL", "BNB"])
print(prices)
# {'BTC': 29540.0, 'ETH': 1847.32, 'SOL': 92.15, 'BNB': 248.70}
Step 3: Calculate Portfolio Value and P&L
import json
def calculate_portfolio(portfolio_file="portfolio.json") -> dict:
with open(portfolio_file) as f:
portfolio = json.load(f)
holdings = portfolio["holdings"]
symbols = [h["symbol"] for h in holdings]
prices = get_prices(symbols)
results = []
total_value = 0
total_invested = 0
for holding in holdings:
symbol = holding["symbol"]
amount = holding["amount"]
avg_buy = holding["avg_buy_price"]
current_price = prices.get(symbol)
if current_price is None:
continue
current_value = amount * current_price
invested = amount * avg_buy
pnl = current_value - invested
pnl_pct = ((current_price - avg_buy) / avg_buy) * 100
results.append({
"symbol": symbol,
"amount": amount,
"avg_buy": avg_buy,
"current_price": current_price,
"current_value": current_value,
"invested": invested,
"pnl": pnl,
"pnl_pct": pnl_pct
})
total_value += current_value
total_invested += invested
total_pnl = total_value - total_invested
total_pnl_pct = ((total_value - total_invested) / total_invested) * 100 if total_invested > 0 else 0
return {
"holdings": results,
"total_value": total_value,
"total_invested": total_invested,
"total_pnl": total_pnl,
"total_pnl_pct": total_pnl_pct
}
Step 4: Pretty-Print the Summary
from datetime import datetime
def print_portfolio_summary(data: dict):
print(f"\n{'='*55}")
print(f" PORTFOLIO TRACKER — {datetime.now().strftime('%Y-%m-%d %H:%M')}")
print(f"{'='*55}")
print(f"{'ASSET':<8} {'AMOUNT':<10} {'PRICE':<12} {'VALUE':<12} {'P&L':<12} {'%'}")
print(f"{'-'*55}")
for h in data["holdings"]:
pnl_str = f"${h['pnl']:+,.2f}"
print(f"{h['symbol']:<8} {h['amount']:<10.4f} ${h['current_price']:<11,.2f} ${h['current_value']:<11,.2f} {pnl_str:<12} {h['pnl_pct']:+.1f}%")
print(f"{'='*55}")
print(f"Total Value: ${data['total_value']:,.2f}")
print(f"Total Invested: ${data['total_invested']:,.2f}")
pnl_symbol = "+" if data['total_pnl'] >= 0 else ""
print(f"Total P&L: ${data['total_pnl']:+,.2f} ({data['total_pnl_pct']:+.2f}%)")
print(f"{'='*55}")
# Run it
data = calculate_portfolio()
print_portfolio_summary(data)
Output:
=======================================================
PORTFOLIO TRACKER — 2024-03-22 09:15
=======================================================
ASSET AMOUNT PRICE VALUE P&L %
-------------------------------------------------------
BTC 0.0500 $29,540.00 $1,477.00 -$23.00 -1.5%
ETH 1.5000 $1,847.32 $2,770.98 +$70.98 +2.6%
SOL 20.0000 $92.15 $1,843.00 +$143.00 +8.4%
BNB 3.0000 $248.70 $746.10 -$8.90 -1.2%
=======================================================
Total Value: $6,837.08
Total Invested: $6,655.00
Total P&L: +$182.08 (+2.74%)
=======================================================
Step 5: Save Historical Data
Track your portfolio over time:
from pathlib import Path
import json
from datetime import datetime
HISTORY_FILE = Path("dragonsoul/portfolio_history.json")
def save_snapshot(data: dict):
history = []
if HISTORY_FILE.exists():
history = json.loads(HISTORY_FILE.read_text())
snapshot = {
"timestamp": datetime.now().isoformat(),
"total_value": data["total_value"],
"total_pnl": data["total_pnl"],
"total_pnl_pct": data["total_pnl_pct"]
}
history.append(snapshot)
# Keep last 90 days of snapshots
history = history[-2160:] # 24 per day * 90 days
HISTORY_FILE.parent.mkdir(exist_ok=True)
HISTORY_FILE.write_text(json.dumps(history, indent=2))
Step 6: Add Alerts
Alert when portfolio moves significantly:
TELEGRAM_TOKEN = "your_bot_token"
CHAT_ID = "your_chat_id"
def check_and_alert(data: dict, previous_value: float):
if previous_value == 0:
return
change_pct = ((data["total_value"] - previous_value) / previous_value) * 100
if abs(change_pct) >= 5: # Alert on 5% swings
emoji = "🚀" if change_pct > 0 else "📉"
msg = f"{emoji} Portfolio moved {change_pct:+.1f}%!\nTotal: ${data['total_value']:,.2f} (P&L: {data['total_pnl_pct']:+.2f}%)"
requests.post(
f"https://api.telegram.org/bot{TELEGRAM_TOKEN}/sendMessage",
json={"chat_id": CHAT_ID, "text": msg}
)
Step 7: Run on a Schedule
import time
while True:
data = calculate_portfolio()
print_portfolio_summary(data)
save_snapshot(data)
time.sleep(3600) # Check every hour
Or integrate with OpenClaw's felix_loop.py which handles scheduling, logging, and error recovery automatically.
Making It Better
From this foundation, you can add:
- Charts — matplotlib for weekly P&L graphs
- Rebalancing alerts — notify when allocation drifts from target
- Tax tracking — log buys/sells for end-of-year calculation
- Multi-exchange — pull data from Coinbase, Kraken, Binance simultaneously
Full Setup Available
The complete portfolio tracker with OpenClaw integration, Telegram alerts, and historical charting is at dragonwhisper36.gumroad.com. Everything pre-configured, runs locally in minutes.
Top comments (0)