Flask is the perfect framework for building lightweight APIs. In this tutorial, we will build a financial data API with endpoints for stock quotes, portfolio management, and basic analytics. By the end, you will have a deployable API that can serve real financial data.
Why Flask for Financial APIs?
Flask is minimal, fast, and gives you complete control over your application structure. Unlike Django, it does not force opinions about your database or project layout. For financial APIs where you need custom data pipelines and specific response formats, Flask is ideal. It also has excellent library support for data processing with pandas and numpy.
Project Setup
Start by creating a virtual environment and installing dependencies. You will need Flask, Flask-CORS for cross-origin requests, and yfinance for pulling stock data. Optionally, install SQLAlchemy if you want to persist portfolio data.
pip install flask flask-cors yfinance mkdir financial-api && cd financial-api touch app.py
Basic App Structure
Your Flask app will have three main endpoint groups: stock data (get quotes, historical prices), portfolio management (add/remove holdings, calculate value), and analytics (performance comparison, sector breakdown).
from flask import Flask, jsonify, request
from flask_cors import CORS
import yfinance as yf
app = Flask(__name__)
CORS(app)
@app.route('/api/quote/<ticker>')
def get_quote(ticker):
stock = yf.Ticker(ticker)
info = stock.info
return jsonify({
'ticker': ticker.upper(),
'price': info.get('currentPrice'),
'name': info.get('shortName'),
'currency': info.get('currency'),
'market_cap': info.get('marketCap'),
})
@app.route('/api/history/<ticker>')
def get_history(ticker):
period = request.args.get('period', '1mo')
stock = yf.Ticker(ticker)
hist = stock.history(period=period)
data = [
{'date': str(d.date()), 'close': round(r['Close'], 2)}
for d, r in hist.iterrows()
]
return jsonify({'ticker': ticker.upper(), 'data': data})Portfolio Endpoints
For a simple portfolio tracker, store holdings in memory (or a database for production). Create endpoints to add a holding (ticker + quantity + purchase price), remove a holding, list all holdings with current values, and calculate total portfolio value and gain/loss.
portfolio = []
@app.route('/api/portfolio', methods=['GET'])
def get_portfolio():
total_value = 0
total_cost = 0
for h in portfolio:
stock = yf.Ticker(h['ticker'])
price = stock.info.get('currentPrice', 0)
h['current_price'] = price
h['value'] = round(price * h['quantity'], 2)
h['gain'] = round(h['value'] - h['cost'], 2)
total_value += h['value']
total_cost += h['cost']
return jsonify({
'holdings': portfolio,
'total_value': round(total_value, 2),
'total_gain': round(total_value - total_cost, 2),
})
@app.route('/api/portfolio', methods=['POST'])
def add_holding():
data = request.json
holding = {
'ticker': data['ticker'].upper(),
'quantity': data['quantity'],
'purchase_price': data['purchase_price'],
'cost': data['quantity'] * data['purchase_price'],
}
portfolio.append(holding)
return jsonify(holding), 201Error Handling
Always validate inputs and handle errors gracefully. Invalid tickers, missing parameters, and API rate limits all need handling. Use Flask’s error handlers and try/except blocks to return meaningful error messages with appropriate HTTP status codes.
Deployment
For production, use Gunicorn as the WSGI server behind Nginx. Deploy on a VPS or use a platform like Railway or Render. Add rate limiting with Flask-Limiter to prevent abuse. Consider caching stock data with Redis to reduce API calls and improve response times.
gunicorn app:app --bind 0.0.0.0:5000 --workers 4